From 0cf7ef824824205373bfe76628184bea4cd5e1b0 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Wed, 28 Sep 2022 11:56:09 +0200 Subject: [PATCH 01/30] [DEV-622] scaffolded strategies for bitcoin and erc-20 tokens --- src/payment/models/dex/dex.module.ts | 30 +++++++--- .../dex/services/dex-bitcoin.service.ts | 4 ++ .../__tests__/strategies.facade.spec.ts | 56 +++++++++---------- ...=> check-liquidity-evm-crypto.strategy.ts} | 2 +- .../check-liquidity-evm-token.strategy.ts | 11 ++++ .../check-liquidity-bitcoin.strategy.ts | 13 +++++ .../check-liquidity-bsc-crypto.strategy.ts | 10 ++++ ... => check-liquidity-bsc-token.strategy.ts} | 4 +- ...heck-liquidity-ethereum-crypto.strategy.ts | 10 ++++ ...heck-liquidity-ethereum-token.strategy.ts} | 4 +- ...purchase-liquidity-evm-crypto.strategy.ts} | 2 +- .../purchase-liquidity-evm-token.strategy.ts | 14 +++++ .../purchase-liquidity-bitcoin.strategy.ts | 10 ++++ .../purchase-liquidity-bsc-crypto.strategy.ts | 11 ++++ ... purchase-liquidity-bsc-token.strategy.ts} | 4 +- ...hase-liquidity-ethereum-crypto.strategy.ts | 11 ++++ ...hase-liquidity-ethereum-token.strategy.ts} | 4 +- .../dex/strategies/strategies.facade.ts | 16 +++--- src/payment/models/payout/payout.module.ts | 16 ++++-- .../payout/services/payout-bitcoin.service.ts | 4 ++ .../__tests__/strategies.facade.spec.ts | 28 +++++----- .../payout/payout-bitcoin.strategy.ts | 21 +++++++ .../payout/payout-bsc-crypto.strategy.ts | 11 ++++ ...rategy.ts => payout-bsc-token.strategy.ts} | 2 +- .../payout/payout-ethereum-crypto.strategy.ts | 11 ++++ ...y.ts => payout-ethereum-token.strategy.ts} | 2 +- .../payout/strategies/strategies.facade.ts | 8 +-- 27 files changed, 241 insertions(+), 78 deletions(-) create mode 100644 src/payment/models/dex/services/dex-bitcoin.service.ts rename src/payment/models/dex/strategies/check-liquidity/base/{check-liquidity-evm.strategy.ts => check-liquidity-evm-crypto.strategy.ts} (85%) create mode 100644 src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-token.strategy.ts create mode 100644 src/payment/models/dex/strategies/check-liquidity/check-liquidity-bitcoin.strategy.ts create mode 100644 src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-crypto.strategy.ts rename src/payment/models/dex/strategies/check-liquidity/{check-liquidity-bsc.strategy.ts => check-liquidity-bsc-token.strategy.ts} (53%) create mode 100644 src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-crypto.strategy.ts rename src/payment/models/dex/strategies/check-liquidity/{check-liquidity-ethereum.strategy.ts => check-liquidity-ethereum-token.strategy.ts} (55%) rename src/payment/models/dex/strategies/purchase-liquidity/base/{purchase-liquidity-evm.strategy.ts => purchase-liquidity-evm-crypto.strategy.ts} (94%) create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-token.strategy.ts create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bitcoin.strategy.ts create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-crypto.strategy.ts rename src/payment/models/dex/strategies/purchase-liquidity/{purchase-liquidity-bsc.strategy.ts => purchase-liquidity-bsc-token.strategy.ts} (61%) create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy.ts rename src/payment/models/dex/strategies/purchase-liquidity/{purchase-liquidity-ethereum.strategy.ts => purchase-liquidity-ethereum-token.strategy.ts} (62%) create mode 100644 src/payment/models/payout/services/payout-bitcoin.service.ts create mode 100644 src/payment/models/payout/strategies/payout/payout-bitcoin.strategy.ts create mode 100644 src/payment/models/payout/strategies/payout/payout-bsc-crypto.strategy.ts rename src/payment/models/payout/strategies/payout/{payout-bsc.strategy.ts => payout-bsc-token.strategy.ts} (86%) create mode 100644 src/payment/models/payout/strategies/payout/payout-ethereum-crypto.strategy.ts rename src/payment/models/payout/strategies/payout/{payout-ethereum.strategy.ts => payout-ethereum-token.strategy.ts} (86%) diff --git a/src/payment/models/dex/dex.module.ts b/src/payment/models/dex/dex.module.ts index 20ff6ab841..2ba9094320 100644 --- a/src/payment/models/dex/dex.module.ts +++ b/src/payment/models/dex/dex.module.ts @@ -13,13 +13,20 @@ import { CheckLiquidityDeFiChainPoolPairStrategy } from './strategies/check-liqu import { PurchaseLiquidityDeFiChainCryptoStrategy } from './strategies/purchase-liquidity/purchase-liquidity-defichain-crypto.strategy'; import { PurchaseLiquidityDeFiChainPoolPairStrategy } from './strategies/purchase-liquidity/purchase-liquidity-defichain-poolpair.strategy'; import { PurchaseLiquidityDeFiChainStockStrategy } from './strategies/purchase-liquidity/purchase-liquidity-defichain-stock.strategy'; -import { CheckLiquidityEthereumStrategy } from './strategies/check-liquidity/check-liquidity-ethereum.strategy'; +import { CheckLiquidityEthereumCryptoStrategy } from './strategies/check-liquidity/check-liquidity-ethereum-crypto.strategy'; import { DexStrategiesFacade } from './strategies/strategies.facade'; -import { PurchaseLiquidityEthereumStrategy } from './strategies/purchase-liquidity/purchase-liquidity-ethereum.strategy'; +import { PurchaseLiquidityEthereumCryptoStrategy } from './strategies/purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy'; import { BscModule } from 'src/blockchain/bsc/bsc.module'; import { DexBscService } from './services/dex-bsc.service'; -import { PurchaseLiquidityBscStrategy } from './strategies/purchase-liquidity/purchase-liquidity-bsc.strategy'; -import { CheckLiquidityBscStrategy } from './strategies/check-liquidity/check-liquidity-bsc.strategy'; +import { PurchaseLiquidityBscCryptoStrategy } from './strategies/purchase-liquidity/purchase-liquidity-bsc-crypto.strategy'; +import { CheckLiquidityBscCryptoStrategy } from './strategies/check-liquidity/check-liquidity-bsc-crypto.strategy'; +import { DexBitcoinService } from './services/dex-bitcoin.service'; +import { CheckLiquidityBitcoinStrategy } from './strategies/check-liquidity/check-liquidity-bitcoin.strategy'; +import { CheckLiquidityBscTokenStrategy } from './strategies/check-liquidity/check-liquidity-bsc-token.strategy'; +import { CheckLiquidityEthereumTokenStrategy } from './strategies/check-liquidity/check-liquidity-ethereum-token.strategy'; +import { PurchaseLiquidityBitcoinStrategy } from './strategies/purchase-liquidity/purchase-liquidity-bitcoin.strategy'; +import { PurchaseLiquidityBscTokenStrategy } from './strategies/purchase-liquidity/purchase-liquidity-bsc-token.strategy'; +import { PurchaseLiquidityEthereumTokenStrategy } from './strategies/purchase-liquidity/purchase-liquidity-ethereum-token.strategy'; @Module({ imports: [TypeOrmModule.forFeature([LiquidityOrderRepository]), AinModule, EthereumModule, BscModule, SharedModule], @@ -29,17 +36,24 @@ import { CheckLiquidityBscStrategy } from './strategies/check-liquidity/check-li DexDeFiChainService, DexEthereumService, DexBscService, + DexBitcoinService, DexStrategiesFacade, DexService, + CheckLiquidityBitcoinStrategy, + CheckLiquidityBscCryptoStrategy, + CheckLiquidityBscTokenStrategy, CheckLiquidityDeFiChainPoolPairStrategy, CheckLiquidityDeFiChainDefaultStrategy, - CheckLiquidityEthereumStrategy, - CheckLiquidityBscStrategy, + CheckLiquidityEthereumCryptoStrategy, + CheckLiquidityEthereumTokenStrategy, + PurchaseLiquidityBitcoinStrategy, + PurchaseLiquidityBscCryptoStrategy, + PurchaseLiquidityBscTokenStrategy, PurchaseLiquidityDeFiChainCryptoStrategy, PurchaseLiquidityDeFiChainPoolPairStrategy, PurchaseLiquidityDeFiChainStockStrategy, - PurchaseLiquidityEthereumStrategy, - PurchaseLiquidityBscStrategy, + PurchaseLiquidityEthereumCryptoStrategy, + PurchaseLiquidityEthereumTokenStrategy, ], exports: [DexService], }) diff --git a/src/payment/models/dex/services/dex-bitcoin.service.ts b/src/payment/models/dex/services/dex-bitcoin.service.ts new file mode 100644 index 0000000000..db93bfced9 --- /dev/null +++ b/src/payment/models/dex/services/dex-bitcoin.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class DexBitcoinService {} diff --git a/src/payment/models/dex/strategies/__tests__/strategies.facade.spec.ts b/src/payment/models/dex/strategies/__tests__/strategies.facade.spec.ts index 0dfa14c01a..9217a267fb 100644 --- a/src/payment/models/dex/strategies/__tests__/strategies.facade.spec.ts +++ b/src/payment/models/dex/strategies/__tests__/strategies.facade.spec.ts @@ -13,15 +13,15 @@ import { DexBscService } from '../../services/dex-bsc.service'; import { DexDeFiChainService } from '../../services/dex-defichain.service'; import { DexEthereumService } from '../../services/dex-ethereum.service'; import { DexService } from '../../services/dex.service'; -import { CheckLiquidityBscStrategy } from '../check-liquidity/check-liquidity-bsc.strategy'; +import { CheckLiquidityBscCryptoStrategy } from '../check-liquidity/check-liquidity-bsc-crypto.strategy'; import { CheckLiquidityDeFiChainDefaultStrategy } from '../check-liquidity/check-liquidity-defichain-default.strategy'; import { CheckLiquidityDeFiChainPoolPairStrategy } from '../check-liquidity/check-liquidity-defichain-poolpair.strategy'; -import { CheckLiquidityEthereumStrategy } from '../check-liquidity/check-liquidity-ethereum.strategy'; -import { PurchaseLiquidityBscStrategy } from '../purchase-liquidity/purchase-liquidity-bsc.strategy'; +import { CheckLiquidityEthereumCryptoStrategy } from '../check-liquidity/check-liquidity-ethereum-crypto.strategy'; +import { PurchaseLiquidityBscCryptoStrategy } from '../purchase-liquidity/purchase-liquidity-bsc-crypto.strategy'; import { PurchaseLiquidityDeFiChainCryptoStrategy } from '../purchase-liquidity/purchase-liquidity-defichain-crypto.strategy'; import { PurchaseLiquidityDeFiChainPoolPairStrategy } from '../purchase-liquidity/purchase-liquidity-defichain-poolpair.strategy'; import { PurchaseLiquidityDeFiChainStockStrategy } from '../purchase-liquidity/purchase-liquidity-defichain-stock.strategy'; -import { PurchaseLiquidityEthereumStrategy } from '../purchase-liquidity/purchase-liquidity-ethereum.strategy'; +import { PurchaseLiquidityEthereumCryptoStrategy } from '../purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy'; import { CheckLiquidityStrategyAlias, DexStrategiesFacade, PurchaseLiquidityStrategyAlias } from '../strategies.facade'; describe('DexStrategiesFacade', () => { @@ -29,13 +29,13 @@ describe('DexStrategiesFacade', () => { let checkLiquidityDeFiChainPoolPairStrategy: CheckLiquidityDeFiChainPoolPairStrategy; let checkLiquidityDeFiChainDefaultStrategy: CheckLiquidityDeFiChainDefaultStrategy; - let checkLiquidityEthereumStrategy: CheckLiquidityEthereumStrategy; - let checkLiquidityBSCStrategy: CheckLiquidityBscStrategy; + let checkLiquidityEthereumStrategy: CheckLiquidityEthereumCryptoStrategy; + let checkLiquidityBSCStrategy: CheckLiquidityBscCryptoStrategy; let purchaseLiquidityDeFiChainPoolPairStrategy: PurchaseLiquidityDeFiChainPoolPairStrategy; let purchaseLiquidityDeFiChainStockStrategy: PurchaseLiquidityDeFiChainStockStrategy; let purchaseLiquidityDeFiChainCryptoStrategy: PurchaseLiquidityDeFiChainCryptoStrategy; - let purchaseLiquidityEthereumStrategy: PurchaseLiquidityEthereumStrategy; - let purchaseLiquidityBscStrategy: PurchaseLiquidityBscStrategy; + let purchaseLiquidityEthereumStrategy: PurchaseLiquidityEthereumCryptoStrategy; + let purchaseLiquidityBscStrategy: PurchaseLiquidityBscCryptoStrategy; let facade: DexStrategiesFacadeWrapper; @@ -45,8 +45,8 @@ describe('DexStrategiesFacade', () => { checkLiquidityDeFiChainPoolPairStrategy = new CheckLiquidityDeFiChainPoolPairStrategy(); checkLiquidityDeFiChainDefaultStrategy = new CheckLiquidityDeFiChainDefaultStrategy(mock()); - checkLiquidityEthereumStrategy = new CheckLiquidityEthereumStrategy(mock()); - checkLiquidityBSCStrategy = new CheckLiquidityBscStrategy(mock()); + checkLiquidityEthereumStrategy = new CheckLiquidityEthereumCryptoStrategy(mock()); + checkLiquidityBSCStrategy = new CheckLiquidityBscCryptoStrategy(mock()); purchaseLiquidityDeFiChainPoolPairStrategy = new PurchaseLiquidityDeFiChainPoolPairStrategy( nodeService, mock(), @@ -68,11 +68,11 @@ describe('DexStrategiesFacade', () => { mock(), mock(), ); - purchaseLiquidityEthereumStrategy = new PurchaseLiquidityEthereumStrategy( + purchaseLiquidityEthereumStrategy = new PurchaseLiquidityEthereumCryptoStrategy( mock(), mock(), ); - purchaseLiquidityBscStrategy = new PurchaseLiquidityBscStrategy(mock(), mock()); + purchaseLiquidityBscStrategy = new PurchaseLiquidityBscCryptoStrategy(mock(), mock()); facade = new DexStrategiesFacadeWrapper( checkLiquidityDeFiChainPoolPairStrategy, @@ -111,11 +111,11 @@ describe('DexStrategiesFacade', () => { ); expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityStrategyAlias.ETHEREUM_DEFAULT)).toBeInstanceOf( - CheckLiquidityEthereumStrategy, + CheckLiquidityEthereumCryptoStrategy, ); expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityStrategyAlias.BSC_DEFAULT)).toBeInstanceOf( - CheckLiquidityBscStrategy, + CheckLiquidityBscCryptoStrategy, ); }); @@ -148,10 +148,10 @@ describe('DexStrategiesFacade', () => { expect( facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT), - ).toBeInstanceOf(PurchaseLiquidityEthereumStrategy); + ).toBeInstanceOf(PurchaseLiquidityEthereumCryptoStrategy); expect(facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.BSC_DEFAULT)).toBeInstanceOf( - PurchaseLiquidityBscStrategy, + PurchaseLiquidityBscCryptoStrategy, ); }); }); @@ -197,7 +197,7 @@ describe('DexStrategiesFacade', () => { it('gets ETHEREUM_DEFAULT strategy', () => { const strategy = facade.getCheckLiquidityStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); - expect(strategy).toBeInstanceOf(CheckLiquidityEthereumStrategy); + expect(strategy).toBeInstanceOf(CheckLiquidityEthereumCryptoStrategy); }); it('gets BSC_DEFAULT strategy', () => { @@ -205,7 +205,7 @@ describe('DexStrategiesFacade', () => { createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN }), ); - expect(strategy).toBeInstanceOf(CheckLiquidityBscStrategy); + expect(strategy).toBeInstanceOf(CheckLiquidityBscCryptoStrategy); }); it('fails to get strategy for non-supported Blockchain', () => { @@ -233,13 +233,13 @@ describe('DexStrategiesFacade', () => { it('gets ETHEREUM_DEFAULT strategy', () => { const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityStrategyAlias.ETHEREUM_DEFAULT); - expect(strategy).toBeInstanceOf(CheckLiquidityEthereumStrategy); + expect(strategy).toBeInstanceOf(CheckLiquidityEthereumCryptoStrategy); }); it('gets BSC_DEFAULT strategy', () => { const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityStrategyAlias.BSC_DEFAULT); - expect(strategy).toBeInstanceOf(CheckLiquidityBscStrategy); + expect(strategy).toBeInstanceOf(CheckLiquidityBscCryptoStrategy); }); it('fails to get strategy for non-supported Alias', () => { @@ -288,7 +288,7 @@ describe('DexStrategiesFacade', () => { it('gets ETHEREUM_DEFAULT strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); - expect(strategy).toBeInstanceOf(PurchaseLiquidityEthereumStrategy); + expect(strategy).toBeInstanceOf(PurchaseLiquidityEthereumCryptoStrategy); }); it('gets BSC_DEFAULT strategy', () => { @@ -296,7 +296,7 @@ describe('DexStrategiesFacade', () => { createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN }), ); - expect(strategy).toBeInstanceOf(PurchaseLiquidityBscStrategy); + expect(strategy).toBeInstanceOf(PurchaseLiquidityBscCryptoStrategy); }); it('fails to get strategy for non-supported Blockchain', () => { @@ -340,13 +340,13 @@ describe('DexStrategiesFacade', () => { it('gets ETHEREUM_DEFAULT strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT); - expect(strategy).toBeInstanceOf(PurchaseLiquidityEthereumStrategy); + expect(strategy).toBeInstanceOf(PurchaseLiquidityEthereumCryptoStrategy); }); it('gets BSC_DEFAULT strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.BSC_DEFAULT); - expect(strategy).toBeInstanceOf(PurchaseLiquidityBscStrategy); + expect(strategy).toBeInstanceOf(PurchaseLiquidityBscCryptoStrategy); }); it('fails to get strategy for non-supported Alias', () => { @@ -364,13 +364,13 @@ class DexStrategiesFacadeWrapper extends DexStrategiesFacade { constructor( checkLiquidityDeFiChainPoolPairStrategy: CheckLiquidityDeFiChainPoolPairStrategy, checkLiquidityDeFiChainDefaultStrategy: CheckLiquidityDeFiChainDefaultStrategy, - checkLiquidityEthereumStrategy: CheckLiquidityEthereumStrategy, - checkLiquidityBSCStrategy: CheckLiquidityBscStrategy, + checkLiquidityEthereumStrategy: CheckLiquidityEthereumCryptoStrategy, + checkLiquidityBSCStrategy: CheckLiquidityBscCryptoStrategy, purchaseLiquidityDeFiChainPoolPairStrategy: PurchaseLiquidityDeFiChainPoolPairStrategy, purchaseLiquidityDeFiChainStockStrategy: PurchaseLiquidityDeFiChainStockStrategy, purchaseLiquidityDeFiChainCryptoStrategy: PurchaseLiquidityDeFiChainCryptoStrategy, - purchaseLiquidityEthereumStrategy: PurchaseLiquidityEthereumStrategy, - purchaseLiquidityBSCStrategy: PurchaseLiquidityBscStrategy, + purchaseLiquidityEthereumStrategy: PurchaseLiquidityEthereumCryptoStrategy, + purchaseLiquidityBSCStrategy: PurchaseLiquidityBscCryptoStrategy, ) { super( checkLiquidityDeFiChainPoolPairStrategy, diff --git a/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-crypto.strategy.ts similarity index 85% rename from src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-crypto.strategy.ts index 2d7ad8de6e..b1683bb10d 100644 --- a/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-crypto.strategy.ts @@ -2,7 +2,7 @@ import { LiquidityRequest } from '../../../interfaces'; import { DexEvmService } from '../../../services/dex-evm.service'; import { CheckLiquidityStrategy } from './check-liquidity.strategy'; -export class CheckLiquidityEvmStrategy implements CheckLiquidityStrategy { +export class CheckLiquidityEvmCryptoStrategy implements CheckLiquidityStrategy { constructor(protected readonly dexEvmService: DexEvmService) {} async checkLiquidity(request: LiquidityRequest): Promise { diff --git a/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-token.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-token.strategy.ts new file mode 100644 index 0000000000..6906139d18 --- /dev/null +++ b/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-token.strategy.ts @@ -0,0 +1,11 @@ +import { LiquidityRequest } from '../../../interfaces'; +import { DexEvmService } from '../../../services/dex-evm.service'; +import { CheckLiquidityStrategy } from './check-liquidity.strategy'; + +export class CheckLiquidityEvmTokenStrategy implements CheckLiquidityStrategy { + constructor(protected readonly dexEvmService: DexEvmService) {} + + async checkLiquidity(request: LiquidityRequest): Promise { + return 0; + } +} diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bitcoin.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bitcoin.strategy.ts new file mode 100644 index 0000000000..18808bde41 --- /dev/null +++ b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bitcoin.strategy.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@nestjs/common'; +import { LiquidityRequest } from '../../interfaces'; +import { DexBitcoinService } from '../../services/dex-bitcoin.service'; +import { CheckLiquidityStrategy } from './base/check-liquidity.strategy'; + +@Injectable() +export class CheckLiquidityBitcoinStrategy implements CheckLiquidityStrategy { + constructor(private readonly dexBtcService: DexBitcoinService) {} + + async checkLiquidity(request: LiquidityRequest): Promise { + return 0; + } +} diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-crypto.strategy.ts new file mode 100644 index 0000000000..e227b1782e --- /dev/null +++ b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-crypto.strategy.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { DexBscService } from '../../services/dex-bsc.service'; +import { CheckLiquidityEvmCryptoStrategy } from './base/check-liquidity-evm-crypto.strategy'; + +@Injectable() +export class CheckLiquidityBscCryptoStrategy extends CheckLiquidityEvmCryptoStrategy { + constructor(dexBscService: DexBscService) { + super(dexBscService); + } +} diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-token.strategy.ts similarity index 53% rename from src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-token.strategy.ts index 76b793e8b7..511c0a8333 100644 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-token.strategy.ts @@ -1,9 +1,9 @@ import { Injectable } from '@nestjs/common'; import { DexBscService } from '../../services/dex-bsc.service'; -import { CheckLiquidityEvmStrategy } from './base/check-liquidity-evm.strategy'; +import { CheckLiquidityEvmTokenStrategy } from './base/check-liquidity-evm-token.strategy'; @Injectable() -export class CheckLiquidityBscStrategy extends CheckLiquidityEvmStrategy { +export class CheckLiquidityBscTokenStrategy extends CheckLiquidityEvmTokenStrategy { constructor(dexBscService: DexBscService) { super(dexBscService); } diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-crypto.strategy.ts new file mode 100644 index 0000000000..406449c239 --- /dev/null +++ b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-crypto.strategy.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { DexEthereumService } from '../../services/dex-ethereum.service'; +import { CheckLiquidityEvmCryptoStrategy } from './base/check-liquidity-evm-crypto.strategy'; + +@Injectable() +export class CheckLiquidityEthereumCryptoStrategy extends CheckLiquidityEvmCryptoStrategy { + constructor(dexEthereumService: DexEthereumService) { + super(dexEthereumService); + } +} diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-token.strategy.ts similarity index 55% rename from src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-token.strategy.ts index 3d1439d359..387c43fb71 100644 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-token.strategy.ts @@ -1,9 +1,9 @@ import { Injectable } from '@nestjs/common'; import { DexEthereumService } from '../../services/dex-ethereum.service'; -import { CheckLiquidityEvmStrategy } from './base/check-liquidity-evm.strategy'; +import { CheckLiquidityEvmTokenStrategy } from './base/check-liquidity-evm-token.strategy'; @Injectable() -export class CheckLiquidityEthereumStrategy extends CheckLiquidityEvmStrategy { +export class CheckLiquidityEthereumTokenStrategy extends CheckLiquidityEvmTokenStrategy { constructor(dexEthereumService: DexEthereumService) { super(dexEthereumService); } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-crypto.strategy.ts similarity index 94% rename from src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-crypto.strategy.ts index eb69befad3..a4116dea49 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-crypto.strategy.ts @@ -3,7 +3,7 @@ import { LiquidityRequest } from '../../../interfaces'; import { DexEvmService } from '../../../services/dex-evm.service'; import { PurchaseLiquidityStrategy } from './purchase-liquidity.strategy'; -export class PurchaseLiquidityEvmStrategy extends PurchaseLiquidityStrategy { +export class PurchaseLiquidityEvmCryptoStrategy extends PurchaseLiquidityStrategy { constructor(mailService: MailService, protected readonly dexEvmService: DexEvmService) { super(mailService); } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-token.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-token.strategy.ts new file mode 100644 index 0000000000..e693e62f72 --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-token.strategy.ts @@ -0,0 +1,14 @@ +import { MailService } from 'src/shared/services/mail.service'; +import { LiquidityRequest } from '../../../interfaces'; +import { DexEvmService } from '../../../services/dex-evm.service'; +import { PurchaseLiquidityStrategy } from './purchase-liquidity.strategy'; + +export class PurchaseLiquidityEvmTokenStrategy extends PurchaseLiquidityStrategy { + constructor(mailService: MailService, protected readonly dexEvmService: DexEvmService) { + super(mailService); + } + + async purchaseLiquidity(request: LiquidityRequest): Promise { + return; + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bitcoin.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bitcoin.strategy.ts new file mode 100644 index 0000000000..243e59bec5 --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bitcoin.strategy.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { PurchaseLiquidityStrategy } from './base/purchase-liquidity.strategy'; +import { LiquidityRequest } from '../../interfaces'; + +@Injectable() +export class PurchaseLiquidityBitcoinStrategy extends PurchaseLiquidityStrategy { + async purchaseLiquidity(request: LiquidityRequest): Promise { + return; + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-crypto.strategy.ts new file mode 100644 index 0000000000..ee3eb041d8 --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-crypto.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { MailService } from 'src/shared/services/mail.service'; +import { DexBscService } from '../../services/dex-bsc.service'; +import { PurchaseLiquidityEvmCryptoStrategy } from './base/purchase-liquidity-evm-crypto.strategy'; + +@Injectable() +export class PurchaseLiquidityBscCryptoStrategy extends PurchaseLiquidityEvmCryptoStrategy { + constructor(mailService: MailService, dexBscService: DexBscService) { + super(mailService, dexBscService); + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-token.strategy.ts similarity index 61% rename from src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-token.strategy.ts index 0a3b02e48b..a067dc5f26 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-token.strategy.ts @@ -1,10 +1,10 @@ import { Injectable } from '@nestjs/common'; import { MailService } from 'src/shared/services/mail.service'; import { DexBscService } from '../../services/dex-bsc.service'; -import { PurchaseLiquidityEvmStrategy } from './base/purchase-liquidity-evm.strategy'; +import { PurchaseLiquidityEvmTokenStrategy } from './base/purchase-liquidity-evm-token.strategy'; @Injectable() -export class PurchaseLiquidityBscStrategy extends PurchaseLiquidityEvmStrategy { +export class PurchaseLiquidityBscTokenStrategy extends PurchaseLiquidityEvmTokenStrategy { constructor(mailService: MailService, dexBscService: DexBscService) { super(mailService, dexBscService); } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy.ts new file mode 100644 index 0000000000..13c8d4409a --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { MailService } from 'src/shared/services/mail.service'; +import { DexEthereumService } from '../../services/dex-ethereum.service'; +import { PurchaseLiquidityEvmCryptoStrategy } from './base/purchase-liquidity-evm-crypto.strategy'; + +@Injectable() +export class PurchaseLiquidityEthereumCryptoStrategy extends PurchaseLiquidityEvmCryptoStrategy { + constructor(mailService: MailService, dexEthereumService: DexEthereumService) { + super(mailService, dexEthereumService); + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-token.strategy.ts similarity index 62% rename from src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-token.strategy.ts index 149caa473e..545bd92ffc 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-token.strategy.ts @@ -1,10 +1,10 @@ import { Injectable } from '@nestjs/common'; import { MailService } from 'src/shared/services/mail.service'; import { DexEthereumService } from '../../services/dex-ethereum.service'; -import { PurchaseLiquidityEvmStrategy } from './base/purchase-liquidity-evm.strategy'; +import { PurchaseLiquidityEvmTokenStrategy } from './base/purchase-liquidity-evm-token.strategy'; @Injectable() -export class PurchaseLiquidityEthereumStrategy extends PurchaseLiquidityEvmStrategy { +export class PurchaseLiquidityEthereumTokenStrategy extends PurchaseLiquidityEvmTokenStrategy { constructor(mailService: MailService, dexEthereumService: DexEthereumService) { super(mailService, dexEthereumService); } diff --git a/src/payment/models/dex/strategies/strategies.facade.ts b/src/payment/models/dex/strategies/strategies.facade.ts index 8741a375c1..1b6b28b262 100644 --- a/src/payment/models/dex/strategies/strategies.facade.ts +++ b/src/payment/models/dex/strategies/strategies.facade.ts @@ -1,14 +1,14 @@ import { forwardRef, Inject, Injectable } from '@nestjs/common'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; import { Asset, AssetCategory } from 'src/shared/models/asset/asset.entity'; -import { CheckLiquidityBscStrategy } from './check-liquidity/check-liquidity-bsc.strategy'; +import { CheckLiquidityBscCryptoStrategy } from './check-liquidity/check-liquidity-bsc-crypto.strategy'; import { CheckLiquidityDeFiChainDefaultStrategy } from './check-liquidity/check-liquidity-defichain-default.strategy'; -import { CheckLiquidityEthereumStrategy } from './check-liquidity/check-liquidity-ethereum.strategy'; +import { CheckLiquidityEthereumCryptoStrategy } from './check-liquidity/check-liquidity-ethereum-crypto.strategy'; import { CheckLiquidityStrategy } from './check-liquidity/base/check-liquidity.strategy'; import { CheckLiquidityDeFiChainPoolPairStrategy } from './check-liquidity/check-liquidity-defichain-poolpair.strategy'; -import { PurchaseLiquidityBscStrategy } from './purchase-liquidity/purchase-liquidity-bsc.strategy'; +import { PurchaseLiquidityBscCryptoStrategy } from './purchase-liquidity/purchase-liquidity-bsc-crypto.strategy'; import { PurchaseLiquidityDeFiChainCryptoStrategy } from './purchase-liquidity/purchase-liquidity-defichain-crypto.strategy'; -import { PurchaseLiquidityEthereumStrategy } from './purchase-liquidity/purchase-liquidity-ethereum.strategy'; +import { PurchaseLiquidityEthereumCryptoStrategy } from './purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy'; import { PurchaseLiquidityStrategy } from './purchase-liquidity/base/purchase-liquidity.strategy'; import { PurchaseLiquidityDeFiChainPoolPairStrategy } from './purchase-liquidity/purchase-liquidity-defichain-poolpair.strategy'; import { PurchaseLiquidityDeFiChainStockStrategy } from './purchase-liquidity/purchase-liquidity-defichain-stock.strategy'; @@ -36,14 +36,14 @@ export class DexStrategiesFacade { constructor( checkLiquidityDeFiChainPoolPairStrategy: CheckLiquidityDeFiChainPoolPairStrategy, checkLiquidityDeFiChainDefaultStrategy: CheckLiquidityDeFiChainDefaultStrategy, - checkLiquidityEthereumStrategy: CheckLiquidityEthereumStrategy, - checkLiquidityBscStrategy: CheckLiquidityBscStrategy, + checkLiquidityEthereumStrategy: CheckLiquidityEthereumCryptoStrategy, + checkLiquidityBscStrategy: CheckLiquidityBscCryptoStrategy, @Inject(forwardRef(() => PurchaseLiquidityDeFiChainPoolPairStrategy)) purchaseLiquidityDeFiChainPoolPairStrategy: PurchaseLiquidityDeFiChainPoolPairStrategy, purchaseLiquidityDeFiChainStockStrategy: PurchaseLiquidityDeFiChainStockStrategy, purchaseLiquidityDeFiChainCryptoStrategy: PurchaseLiquidityDeFiChainCryptoStrategy, - purchaseLiquidityEthereumStrategy: PurchaseLiquidityEthereumStrategy, - purchaseLiquidityBscStrategy: PurchaseLiquidityBscStrategy, + purchaseLiquidityEthereumStrategy: PurchaseLiquidityEthereumCryptoStrategy, + purchaseLiquidityBscStrategy: PurchaseLiquidityBscCryptoStrategy, ) { this.checkLiquidityStrategies.set( CheckLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR, diff --git a/src/payment/models/payout/payout.module.ts b/src/payment/models/payout/payout.module.ts index 675d34571a..11da8b8d6d 100644 --- a/src/payment/models/payout/payout.module.ts +++ b/src/payment/models/payout/payout.module.ts @@ -12,14 +12,18 @@ import { PayoutDeFiChainService } from './services/payout-defichain.service'; import { PayoutEthereumService } from './services/payout-ethereum.service'; import { PayoutLogService } from './services/payout-log.service'; import { PayoutService } from './services/payout.service'; -import { PayoutBscStrategy } from './strategies/payout/payout-bsc.strategy'; +import { PayoutBscCryptoStrategy } from './strategies/payout/payout-bsc-crypto.strategy'; import { PayoutDeFiChainDFIStrategy } from './strategies/payout/payout-defichain-dfi.strategy'; -import { PayoutEthereumStrategy } from './strategies/payout/payout-ethereum.strategy'; +import { PayoutEthereumCryptoStrategy } from './strategies/payout/payout-ethereum-crypto.strategy'; import { PayoutDeFiChainTokenStrategy } from './strategies/payout/payout-defichain-token.strategy'; import { PrepareBscStrategy } from './strategies/prepare/prepare-bsc.strategy'; import { PrepareDeFiChainStrategy } from './strategies/prepare/prepare-defichain.strategy'; import { PrepareEthereumStrategy } from './strategies/prepare/prepare-ethereum.strategy'; import { PayoutStrategiesFacade } from './strategies/strategies.facade'; +import { PayoutBitcoinService } from './services/payout-bitcoin.service'; +import { PayoutBitcoinStrategy } from './strategies/payout/payout-bitcoin.strategy'; +import { PayoutBscTokenStrategy } from './strategies/payout/payout-bsc-token.strategy'; +import { PayoutEthereumTokenStrategy } from './strategies/payout/payout-ethereum-token.strategy'; @Module({ imports: [ @@ -35,13 +39,17 @@ import { PayoutStrategiesFacade } from './strategies/strategies.facade'; PayoutOrderFactory, PayoutLogService, PayoutService, + PayoutBitcoinService, PayoutDeFiChainService, PayoutEthereumService, PayoutBscService, + PayoutBitcoinStrategy, + PayoutBscCryptoStrategy, + PayoutBscTokenStrategy, PayoutDeFiChainDFIStrategy, PayoutDeFiChainTokenStrategy, - PayoutEthereumStrategy, - PayoutBscStrategy, + PayoutEthereumCryptoStrategy, + PayoutEthereumTokenStrategy, PrepareDeFiChainStrategy, PrepareEthereumStrategy, PrepareBscStrategy, diff --git a/src/payment/models/payout/services/payout-bitcoin.service.ts b/src/payment/models/payout/services/payout-bitcoin.service.ts new file mode 100644 index 0000000000..1768af3dfd --- /dev/null +++ b/src/payment/models/payout/services/payout-bitcoin.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class PayoutBitcoinService {} diff --git a/src/payment/models/payout/strategies/__tests__/strategies.facade.spec.ts b/src/payment/models/payout/strategies/__tests__/strategies.facade.spec.ts index d86ef185ac..1dca74caa9 100644 --- a/src/payment/models/payout/strategies/__tests__/strategies.facade.spec.ts +++ b/src/payment/models/payout/strategies/__tests__/strategies.facade.spec.ts @@ -7,10 +7,10 @@ import { PayoutOrderRepository } from '../../repositories/payout-order.repositor import { PayoutBscService } from '../../services/payout-bsc.service'; import { PayoutDeFiChainService } from '../../services/payout-defichain.service'; import { PayoutEthereumService } from '../../services/payout-ethereum.service'; -import { PayoutBscStrategy } from '../payout/payout-bsc.strategy'; +import { PayoutBscCryptoStrategy } from '../payout/payout-bsc-crypto.strategy'; import { PayoutDeFiChainDFIStrategy } from '../payout/payout-defichain-dfi.strategy'; import { PayoutDeFiChainTokenStrategy } from '../payout/payout-defichain-token.strategy'; -import { PayoutEthereumStrategy } from '../payout/payout-ethereum.strategy'; +import { PayoutEthereumCryptoStrategy } from '../payout/payout-ethereum-crypto.strategy'; import { PrepareBscStrategy } from '../prepare/prepare-bsc.strategy'; import { PrepareDeFiChainStrategy } from '../prepare/prepare-defichain.strategy'; import { PrepareEthereumStrategy } from '../prepare/prepare-ethereum.strategy'; @@ -19,8 +19,8 @@ import { PayoutStrategiesFacade, PayoutStrategyAlias, PrepareStrategyAlias } fro describe('PayoutStrategiesFacade', () => { let payoutDFIStrategy: PayoutDeFiChainDFIStrategy; let payoutTokenStrategy: PayoutDeFiChainTokenStrategy; - let payoutETHStrategy: PayoutEthereumStrategy; - let payoutBSCStrategy: PayoutBscStrategy; + let payoutETHStrategy: PayoutEthereumCryptoStrategy; + let payoutBSCStrategy: PayoutBscCryptoStrategy; let prepareOnDefichainStrategy: PrepareDeFiChainStrategy; let prepareOnEthereumStrategy: PrepareEthereumStrategy; let prepareOnBscStrategy: PrepareBscStrategy; @@ -39,8 +39,8 @@ describe('PayoutStrategiesFacade', () => { mock(), mock(), ); - payoutETHStrategy = new PayoutEthereumStrategy(mock(), mock()); - payoutBSCStrategy = new PayoutBscStrategy(mock(), mock()); + payoutETHStrategy = new PayoutEthereumCryptoStrategy(mock(), mock()); + payoutBSCStrategy = new PayoutBscCryptoStrategy(mock(), mock()); prepareOnDefichainStrategy = new PrepareDeFiChainStrategy( mock(), mock(), @@ -84,10 +84,10 @@ describe('PayoutStrategiesFacade', () => { ); expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.ETHEREUM_DEFAULT)).toBeInstanceOf( - PayoutEthereumStrategy, + PayoutEthereumCryptoStrategy, ); - expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.BSC_DEFAULT)).toBeInstanceOf(PayoutBscStrategy); + expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.BSC_DEFAULT)).toBeInstanceOf(PayoutBscCryptoStrategy); }); it('adds all prepareStrategies to a map', () => { @@ -118,13 +118,13 @@ describe('PayoutStrategiesFacade', () => { it('gets ETHEREUM_DEFAULT strategy', () => { const strategy = facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); - expect(strategy).toBeInstanceOf(PayoutEthereumStrategy); + expect(strategy).toBeInstanceOf(PayoutEthereumCryptoStrategy); }); it('gets BSC_DEFAULT strategy', () => { const strategy = facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN })); - expect(strategy).toBeInstanceOf(PayoutBscStrategy); + expect(strategy).toBeInstanceOf(PayoutBscCryptoStrategy); }); it('gets DEFICHAIN_DFI strategy', () => { @@ -172,13 +172,13 @@ describe('PayoutStrategiesFacade', () => { it('gets ETHEREUM_DEFAULT strategy', () => { const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_DEFAULT); - expect(strategy).toBeInstanceOf(PayoutEthereumStrategy); + expect(strategy).toBeInstanceOf(PayoutEthereumCryptoStrategy); }); it('gets BSC_DEFAULT strategy', () => { const strategyCrypto = facade.getPayoutStrategy(PayoutStrategyAlias.BSC_DEFAULT); - expect(strategyCrypto).toBeInstanceOf(PayoutBscStrategy); + expect(strategyCrypto).toBeInstanceOf(PayoutBscCryptoStrategy); }); it('gets DEFICHAIN_DFI strategy', () => { @@ -270,8 +270,8 @@ class PayoutStrategiesFacadeWrapper extends PayoutStrategiesFacade { constructor( payoutDFIStrategy: PayoutDeFiChainDFIStrategy, payoutTokenStrategy: PayoutDeFiChainTokenStrategy, - payoutETHStrategy: PayoutEthereumStrategy, - payoutBSCStrategy: PayoutBscStrategy, + payoutETHStrategy: PayoutEthereumCryptoStrategy, + payoutBSCStrategy: PayoutBscCryptoStrategy, prepareOnDefichainStrategy: PrepareDeFiChainStrategy, prepareOnEthereumStrategy: PrepareEthereumStrategy, prepareOnBscStrategy: PrepareBscStrategy, diff --git a/src/payment/models/payout/strategies/payout/payout-bitcoin.strategy.ts b/src/payment/models/payout/strategies/payout/payout-bitcoin.strategy.ts new file mode 100644 index 0000000000..8a20d38bf4 --- /dev/null +++ b/src/payment/models/payout/strategies/payout/payout-bitcoin.strategy.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@nestjs/common'; +import { PayoutOrder } from '../../entities/payout-order.entity'; +import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; +import { PayoutBitcoinService } from '../../services/payout-bitcoin.service'; +import { PayoutStrategy } from './base/payout.strategy'; + +@Injectable() +export class PayoutBitcoinStrategy implements PayoutStrategy { + constructor( + protected readonly bitcoinService: PayoutBitcoinService, + protected readonly payoutOrderRepo: PayoutOrderRepository, + ) {} + + doPayout(orders: PayoutOrder[]): Promise { + throw new Error('Method not implemented.'); + } + + checkPayoutCompletion(order: PayoutOrder): Promise { + throw new Error('Method not implemented.'); + } +} diff --git a/src/payment/models/payout/strategies/payout/payout-bsc-crypto.strategy.ts b/src/payment/models/payout/strategies/payout/payout-bsc-crypto.strategy.ts new file mode 100644 index 0000000000..eee1edc2f6 --- /dev/null +++ b/src/payment/models/payout/strategies/payout/payout-bsc-crypto.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; +import { PayoutBscService } from '../../services/payout-bsc.service'; +import { PayoutEvmStrategy } from './base/payout-evm.strategy'; + +@Injectable() +export class PayoutBscCryptoStrategy extends PayoutEvmStrategy { + constructor(bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { + super(bscService, payoutOrderRepo); + } +} diff --git a/src/payment/models/payout/strategies/payout/payout-bsc.strategy.ts b/src/payment/models/payout/strategies/payout/payout-bsc-token.strategy.ts similarity index 86% rename from src/payment/models/payout/strategies/payout/payout-bsc.strategy.ts rename to src/payment/models/payout/strategies/payout/payout-bsc-token.strategy.ts index ae60d6506e..b976cd66ae 100644 --- a/src/payment/models/payout/strategies/payout/payout-bsc.strategy.ts +++ b/src/payment/models/payout/strategies/payout/payout-bsc-token.strategy.ts @@ -4,7 +4,7 @@ import { PayoutBscService } from '../../services/payout-bsc.service'; import { PayoutEvmStrategy } from './base/payout-evm.strategy'; @Injectable() -export class PayoutBscStrategy extends PayoutEvmStrategy { +export class PayoutBscTokenStrategy extends PayoutEvmStrategy { constructor(bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { super(bscService, payoutOrderRepo); } diff --git a/src/payment/models/payout/strategies/payout/payout-ethereum-crypto.strategy.ts b/src/payment/models/payout/strategies/payout/payout-ethereum-crypto.strategy.ts new file mode 100644 index 0000000000..9296d038f9 --- /dev/null +++ b/src/payment/models/payout/strategies/payout/payout-ethereum-crypto.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; +import { PayoutEthereumService } from '../../services/payout-ethereum.service'; +import { PayoutEvmStrategy } from './base/payout-evm.strategy'; + +@Injectable() +export class PayoutEthereumCryptoStrategy extends PayoutEvmStrategy { + constructor(ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { + super(ethereumService, payoutOrderRepo); + } +} diff --git a/src/payment/models/payout/strategies/payout/payout-ethereum.strategy.ts b/src/payment/models/payout/strategies/payout/payout-ethereum-token.strategy.ts similarity index 86% rename from src/payment/models/payout/strategies/payout/payout-ethereum.strategy.ts rename to src/payment/models/payout/strategies/payout/payout-ethereum-token.strategy.ts index d24f949163..66aa1c426c 100644 --- a/src/payment/models/payout/strategies/payout/payout-ethereum.strategy.ts +++ b/src/payment/models/payout/strategies/payout/payout-ethereum-token.strategy.ts @@ -4,7 +4,7 @@ import { PayoutEthereumService } from '../../services/payout-ethereum.service'; import { PayoutEvmStrategy } from './base/payout-evm.strategy'; @Injectable() -export class PayoutEthereumStrategy extends PayoutEvmStrategy { +export class PayoutEthereumTokenStrategy extends PayoutEvmStrategy { constructor(ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { super(ethereumService, payoutOrderRepo); } diff --git a/src/payment/models/payout/strategies/strategies.facade.ts b/src/payment/models/payout/strategies/strategies.facade.ts index ba12becb9a..71ce7ef349 100644 --- a/src/payment/models/payout/strategies/strategies.facade.ts +++ b/src/payment/models/payout/strategies/strategies.facade.ts @@ -1,9 +1,9 @@ import { Injectable } from '@nestjs/common'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; import { Asset } from 'src/shared/models/asset/asset.entity'; -import { PayoutBscStrategy } from './payout/payout-bsc.strategy'; +import { PayoutBscCryptoStrategy } from './payout/payout-bsc-crypto.strategy'; import { PayoutDeFiChainDFIStrategy } from './payout/payout-defichain-dfi.strategy'; -import { PayoutEthereumStrategy } from './payout/payout-ethereum.strategy'; +import { PayoutEthereumCryptoStrategy } from './payout/payout-ethereum-crypto.strategy'; import { PayoutDeFiChainTokenStrategy } from './payout/payout-defichain-token.strategy'; import { PayoutStrategy } from './payout/base/payout.strategy'; import { PrepareBscStrategy } from './prepare/prepare-bsc.strategy'; @@ -32,8 +32,8 @@ export class PayoutStrategiesFacade { constructor( payoutDFIStrategy: PayoutDeFiChainDFIStrategy, payoutTokenStrategy: PayoutDeFiChainTokenStrategy, - payoutEthStrategy: PayoutEthereumStrategy, - payoutBscStrategy: PayoutBscStrategy, + payoutEthStrategy: PayoutEthereumCryptoStrategy, + payoutBscStrategy: PayoutBscCryptoStrategy, prepareOnDefichainStrategy: PrepareDeFiChainStrategy, prepareOnEthereumStrategy: PrepareEthereumStrategy, prepareOnBscStrategy: PrepareBscStrategy, From 21c611ad8f620b353a3d4f14b308ec4ff98c4250 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Thu, 29 Sep 2022 10:58:01 +0200 Subject: [PATCH 02/30] [DEV-622] restructured dex strategies --- src/payment/models/dex/dex.module.ts | 70 ++-- .../models/dex/services/dex.service.ts | 12 +- .../__tests__/strategies.facade.spec.ts | 395 ------------------ .../__tests__/check-liquidity.facade.spec.ts | 187 +++++++++ .../check-liquidity-bsc-crypto.strategy.ts | 10 - .../check-liquidity-bsc-token.strategy.ts | 10 - ...heck-liquidity-ethereum-crypto.strategy.ts | 10 - ...check-liquidity-ethereum-token.strategy.ts | 10 - .../check-liquidity/check-liquidity.facade.ts | 68 +++ .../base/check-liquidity.strategy.ts | 2 +- .../base/evm-crypto.strategy.ts} | 6 +- .../base/evm-token.strategy.ts} | 6 +- .../bitcoin.strategy.ts} | 6 +- .../impl/bsc-crypto.strategy.ts | 10 + .../impl/bsc-token.strategy.ts | 10 + .../defichain-default.strategy.ts} | 8 +- .../defichain-poolpair.strategy.ts} | 2 +- .../impl/ethereum-crypto.strategy.ts | 10 + .../impl/ethereum-token.strategy.ts | 10 + .../purchase-liquidity.facade.spec.ts | 231 ++++++++++ .../base/defichain-non-poolpair.strategy.ts} | 14 +- .../base/evm-crypto.strategy.ts} | 6 +- .../base/evm-token.strategy.ts} | 6 +- .../base/purchase-liquidity.strategy.ts | 6 +- .../bitcoin.strategy.ts} | 4 +- .../impl/bsc-crypto.strategy.ts | 11 + .../impl/bsc-token.strategy.ts | 11 + .../impl/defichain-crypto.strategy.ts | 18 + .../defichain-poolpair.strategy.ts} | 18 +- .../impl/defichain-stock.strategy.ts | 18 + .../impl/ethereum-crypto.strategy.ts | 11 + .../impl/ethereum-token.strategy.ts | 11 + .../purchase-liquidity-bsc-crypto.strategy.ts | 11 - .../purchase-liquidity-bsc-token.strategy.ts | 11 - ...ase-liquidity-defichain-crypto.strategy.ts | 18 - ...hase-liquidity-defichain-stock.strategy.ts | 18 - ...hase-liquidity-ethereum-crypto.strategy.ts | 11 - ...chase-liquidity-ethereum-token.strategy.ts | 11 - .../purchase-liquidity.facade.ts | 74 ++++ .../dex/strategies/strategies.facade.ts | 151 ------- 40 files changed, 765 insertions(+), 747 deletions(-) delete mode 100644 src/payment/models/dex/strategies/__tests__/strategies.facade.spec.ts create mode 100644 src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts delete mode 100644 src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-crypto.strategy.ts delete mode 100644 src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-token.strategy.ts delete mode 100644 src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-crypto.strategy.ts delete mode 100644 src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-token.strategy.ts create mode 100644 src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts rename src/payment/models/dex/strategies/check-liquidity/{ => impl}/base/check-liquidity.strategy.ts (64%) rename src/payment/models/dex/strategies/check-liquidity/{base/check-liquidity-evm-crypto.strategy.ts => impl/base/evm-crypto.strategy.ts} (63%) rename src/payment/models/dex/strategies/check-liquidity/{base/check-liquidity-evm-token.strategy.ts => impl/base/evm-token.strategy.ts} (52%) rename src/payment/models/dex/strategies/check-liquidity/{check-liquidity-bitcoin.strategy.ts => impl/bitcoin.strategy.ts} (58%) create mode 100644 src/payment/models/dex/strategies/check-liquidity/impl/bsc-crypto.strategy.ts create mode 100644 src/payment/models/dex/strategies/check-liquidity/impl/bsc-token.strategy.ts rename src/payment/models/dex/strategies/check-liquidity/{check-liquidity-defichain-default.strategy.ts => impl/defichain-default.strategy.ts} (69%) rename src/payment/models/dex/strategies/check-liquidity/{check-liquidity-defichain-poolpair.strategy.ts => impl/defichain-poolpair.strategy.ts} (74%) create mode 100644 src/payment/models/dex/strategies/check-liquidity/impl/ethereum-crypto.strategy.ts create mode 100644 src/payment/models/dex/strategies/check-liquidity/impl/ethereum-token.strategy.ts create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts rename src/payment/models/dex/strategies/purchase-liquidity/{base/purchase-liquidity-defichain-non-poolpair.strategy.ts => impl/base/defichain-non-poolpair.strategy.ts} (82%) rename src/payment/models/dex/strategies/purchase-liquidity/{base/purchase-liquidity-evm-crypto.strategy.ts => impl/base/evm-crypto.strategy.ts} (86%) rename src/payment/models/dex/strategies/purchase-liquidity/{base/purchase-liquidity-evm-token.strategy.ts => impl/base/evm-token.strategy.ts} (62%) rename src/payment/models/dex/strategies/purchase-liquidity/{ => impl}/base/purchase-liquidity.strategy.ts (75%) rename src/payment/models/dex/strategies/purchase-liquidity/{purchase-liquidity-bitcoin.strategy.ts => impl/bitcoin.strategy.ts} (62%) create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-crypto.strategy.ts create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-token.strategy.ts create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-crypto.strategy.ts rename src/payment/models/dex/strategies/purchase-liquidity/{purchase-liquidity-defichain-poolpair.strategy.ts => impl/defichain-poolpair.strategy.ts} (91%) create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-stock.strategy.ts create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-crypto.strategy.ts create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-token.strategy.ts delete mode 100644 src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-crypto.strategy.ts delete mode 100644 src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-token.strategy.ts delete mode 100644 src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-crypto.strategy.ts delete mode 100644 src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-stock.strategy.ts delete mode 100644 src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy.ts delete mode 100644 src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-token.strategy.ts create mode 100644 src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts delete mode 100644 src/payment/models/dex/strategies/strategies.facade.ts diff --git a/src/payment/models/dex/dex.module.ts b/src/payment/models/dex/dex.module.ts index 2ba9094320..fda9de3620 100644 --- a/src/payment/models/dex/dex.module.ts +++ b/src/payment/models/dex/dex.module.ts @@ -2,58 +2,60 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { AinModule } from 'src/blockchain/ain/ain.module'; import { EthereumModule } from 'src/blockchain/ethereum/ethereum.module'; +import { BscModule } from 'src/blockchain/bsc/bsc.module'; import { SharedModule } from 'src/shared/shared.module'; import { LiquidityOrderFactory } from './factories/liquidity-order.factory'; import { LiquidityOrderRepository } from './repositories/liquidity-order.repository'; import { DexEthereumService } from './services/dex-ethereum.service'; import { DexService } from './services/dex.service'; import { DexDeFiChainService } from './services/dex-defichain.service'; -import { CheckLiquidityDeFiChainDefaultStrategy } from './strategies/check-liquidity/check-liquidity-defichain-default.strategy'; -import { CheckLiquidityDeFiChainPoolPairStrategy } from './strategies/check-liquidity/check-liquidity-defichain-poolpair.strategy'; -import { PurchaseLiquidityDeFiChainCryptoStrategy } from './strategies/purchase-liquidity/purchase-liquidity-defichain-crypto.strategy'; -import { PurchaseLiquidityDeFiChainPoolPairStrategy } from './strategies/purchase-liquidity/purchase-liquidity-defichain-poolpair.strategy'; -import { PurchaseLiquidityDeFiChainStockStrategy } from './strategies/purchase-liquidity/purchase-liquidity-defichain-stock.strategy'; -import { CheckLiquidityEthereumCryptoStrategy } from './strategies/check-liquidity/check-liquidity-ethereum-crypto.strategy'; -import { DexStrategiesFacade } from './strategies/strategies.facade'; -import { PurchaseLiquidityEthereumCryptoStrategy } from './strategies/purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy'; -import { BscModule } from 'src/blockchain/bsc/bsc.module'; import { DexBscService } from './services/dex-bsc.service'; -import { PurchaseLiquidityBscCryptoStrategy } from './strategies/purchase-liquidity/purchase-liquidity-bsc-crypto.strategy'; -import { CheckLiquidityBscCryptoStrategy } from './strategies/check-liquidity/check-liquidity-bsc-crypto.strategy'; import { DexBitcoinService } from './services/dex-bitcoin.service'; -import { CheckLiquidityBitcoinStrategy } from './strategies/check-liquidity/check-liquidity-bitcoin.strategy'; -import { CheckLiquidityBscTokenStrategy } from './strategies/check-liquidity/check-liquidity-bsc-token.strategy'; -import { CheckLiquidityEthereumTokenStrategy } from './strategies/check-liquidity/check-liquidity-ethereum-token.strategy'; -import { PurchaseLiquidityBitcoinStrategy } from './strategies/purchase-liquidity/purchase-liquidity-bitcoin.strategy'; -import { PurchaseLiquidityBscTokenStrategy } from './strategies/purchase-liquidity/purchase-liquidity-bsc-token.strategy'; -import { PurchaseLiquidityEthereumTokenStrategy } from './strategies/purchase-liquidity/purchase-liquidity-ethereum-token.strategy'; +import { CheckLiquidityStrategies } from './strategies/check-liquidity/check-liquidity.facade'; +import { PurchaseLiquidityStrategies } from './strategies/purchase-liquidity/purchase-liquidity.facade'; +import { DeFiChainDefaultStrategy as DeFiChainDefaultStrategyCL } from './strategies/check-liquidity/impl/defichain-default.strategy'; +import { DeFiChainPoolPairStrategy as DeFiChainPoolPairStrategyCL } from './strategies/check-liquidity/impl/defichain-poolpair.strategy'; +import { EthereumCryptoStrategy as EthereumCryptoStrategyCL } from './strategies/check-liquidity/impl/ethereum-crypto.strategy'; +import { BscCryptoStrategy as BscCryptoStrategyCL } from './strategies/check-liquidity/impl/bsc-crypto.strategy'; +import { BitcoinStrategy as BitcoinStrategyCL } from './strategies/check-liquidity/impl/bitcoin.strategy'; +import { BscTokenStrategy as BscTokenStrategyCL } from './strategies/check-liquidity/impl/bsc-token.strategy'; +import { EthereumTokenStrategy as EthereumTokenStrategyCL } from './strategies/check-liquidity/impl/ethereum-token.strategy'; +import { DeFiChainCryptoStrategy as DeFiChainCryptoStrategyPL } from './strategies/purchase-liquidity/impl/defichain-crypto.strategy'; +import { DeFiChainPoolPairStrategy as DeFiChainPoolPairStrategyPL } from './strategies/purchase-liquidity/impl/defichain-poolpair.strategy'; +import { DeFiChainStockStrategy as DeFiChainStockStrategyPL } from './strategies/purchase-liquidity/impl/defichain-stock.strategy'; +import { EthereumCryptoStrategy as EthereumCryptoStrategyPL } from './strategies/purchase-liquidity/impl/ethereum-crypto.strategy'; +import { BscCryptoStrategy as BscCryptoStrategyPL } from './strategies/purchase-liquidity/impl/bsc-crypto.strategy'; +import { BitcoinStrategy as BitcoinStrategyPL } from './strategies/purchase-liquidity/impl/bitcoin.strategy'; +import { BscTokenStrategy as BscTokenStrategyPL } from './strategies/purchase-liquidity/impl/bsc-token.strategy'; +import { EthereumTokenStrategy as EthereumTokenStrategyPL } from './strategies/purchase-liquidity/impl/ethereum-token.strategy'; @Module({ imports: [TypeOrmModule.forFeature([LiquidityOrderRepository]), AinModule, EthereumModule, BscModule, SharedModule], controllers: [], providers: [ + DexService, LiquidityOrderFactory, DexDeFiChainService, DexEthereumService, DexBscService, DexBitcoinService, - DexStrategiesFacade, - DexService, - CheckLiquidityBitcoinStrategy, - CheckLiquidityBscCryptoStrategy, - CheckLiquidityBscTokenStrategy, - CheckLiquidityDeFiChainPoolPairStrategy, - CheckLiquidityDeFiChainDefaultStrategy, - CheckLiquidityEthereumCryptoStrategy, - CheckLiquidityEthereumTokenStrategy, - PurchaseLiquidityBitcoinStrategy, - PurchaseLiquidityBscCryptoStrategy, - PurchaseLiquidityBscTokenStrategy, - PurchaseLiquidityDeFiChainCryptoStrategy, - PurchaseLiquidityDeFiChainPoolPairStrategy, - PurchaseLiquidityDeFiChainStockStrategy, - PurchaseLiquidityEthereumCryptoStrategy, - PurchaseLiquidityEthereumTokenStrategy, + CheckLiquidityStrategies, + PurchaseLiquidityStrategies, + DeFiChainDefaultStrategyCL, + DeFiChainPoolPairStrategyCL, + EthereumCryptoStrategyCL, + BscCryptoStrategyCL, + BitcoinStrategyCL, + BscTokenStrategyCL, + EthereumTokenStrategyCL, + DeFiChainCryptoStrategyPL, + DeFiChainPoolPairStrategyPL, + DeFiChainStockStrategyPL, + EthereumCryptoStrategyPL, + BscCryptoStrategyPL, + BitcoinStrategyPL, + BscTokenStrategyPL, + EthereumTokenStrategyPL, ], exports: [DexService], }) diff --git a/src/payment/models/dex/services/dex.service.ts b/src/payment/models/dex/services/dex.service.ts index 111bad8d68..88e6d761c5 100644 --- a/src/payment/models/dex/services/dex.service.ts +++ b/src/payment/models/dex/services/dex.service.ts @@ -9,15 +9,17 @@ import { Interval } from '@nestjs/schedule'; import { Lock } from 'src/shared/lock'; import { Not, IsNull } from 'typeorm'; import { LiquidityOrderFactory } from '../factories/liquidity-order.factory'; -import { DexStrategiesFacade } from '../strategies/strategies.facade'; +import { CheckLiquidityStrategies } from '../strategies/check-liquidity/check-liquidity.facade'; import { LiquidityRequest, TransferRequest } from '../interfaces'; +import { PurchaseLiquidityStrategies } from '../strategies/purchase-liquidity/purchase-liquidity.facade'; @Injectable() export class DexService { private readonly verifyPurchaseOrdersLock = new Lock(1800); constructor( - private readonly strategies: DexStrategiesFacade, + private readonly checkStrategies: CheckLiquidityStrategies, + private readonly purchaseStrategies: PurchaseLiquidityStrategies, private readonly dexDeFiChainService: DexDeFiChainService, private readonly liquidityOrderRepo: LiquidityOrderRepository, private readonly liquidityOrderFactory: LiquidityOrderFactory, @@ -29,7 +31,7 @@ export class DexService { const { context, correlationId, targetAsset } = request; try { - const strategy = this.strategies.getCheckLiquidityStrategy(targetAsset); + const strategy = this.checkStrategies.getCheckLiquidityStrategy(targetAsset); return strategy.checkLiquidity(request); } catch (e) { @@ -50,7 +52,7 @@ export class DexService { try { console.info(`Reserving ${targetAsset.dexName} liquidity. Context: ${context}. Correlation ID: ${correlationId}`); - const strategy = this.strategies.getCheckLiquidityStrategy(targetAsset); + const strategy = this.checkStrategies.getCheckLiquidityStrategy(targetAsset); const liquidity = await strategy.checkLiquidity(request); @@ -80,7 +82,7 @@ export class DexService { async purchaseLiquidity(request: LiquidityRequest): Promise { const { context, correlationId, targetAsset } = request; - const strategy = this.strategies.getPurchaseLiquidityStrategy(targetAsset); + const strategy = this.purchaseStrategies.getPurchaseLiquidityStrategy(targetAsset); if (!strategy) { throw new Error(`No purchase liquidity strategy for asset category ${targetAsset?.category}`); diff --git a/src/payment/models/dex/strategies/__tests__/strategies.facade.spec.ts b/src/payment/models/dex/strategies/__tests__/strategies.facade.spec.ts deleted file mode 100644 index 9217a267fb..0000000000 --- a/src/payment/models/dex/strategies/__tests__/strategies.facade.spec.ts +++ /dev/null @@ -1,395 +0,0 @@ -import { mock } from 'jest-mock-extended'; -import { BehaviorSubject } from 'rxjs'; -import { NodeService } from 'src/blockchain/ain/node/node.service'; -import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { AssetCategory } from 'src/shared/models/asset/asset.entity'; -import { AssetService } from 'src/shared/models/asset/asset.service'; -import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; -import { SettingService } from 'src/shared/models/setting/setting.service'; -import { MailService } from 'src/shared/services/mail.service'; -import { LiquidityOrderFactory } from '../../factories/liquidity-order.factory'; -import { LiquidityOrderRepository } from '../../repositories/liquidity-order.repository'; -import { DexBscService } from '../../services/dex-bsc.service'; -import { DexDeFiChainService } from '../../services/dex-defichain.service'; -import { DexEthereumService } from '../../services/dex-ethereum.service'; -import { DexService } from '../../services/dex.service'; -import { CheckLiquidityBscCryptoStrategy } from '../check-liquidity/check-liquidity-bsc-crypto.strategy'; -import { CheckLiquidityDeFiChainDefaultStrategy } from '../check-liquidity/check-liquidity-defichain-default.strategy'; -import { CheckLiquidityDeFiChainPoolPairStrategy } from '../check-liquidity/check-liquidity-defichain-poolpair.strategy'; -import { CheckLiquidityEthereumCryptoStrategy } from '../check-liquidity/check-liquidity-ethereum-crypto.strategy'; -import { PurchaseLiquidityBscCryptoStrategy } from '../purchase-liquidity/purchase-liquidity-bsc-crypto.strategy'; -import { PurchaseLiquidityDeFiChainCryptoStrategy } from '../purchase-liquidity/purchase-liquidity-defichain-crypto.strategy'; -import { PurchaseLiquidityDeFiChainPoolPairStrategy } from '../purchase-liquidity/purchase-liquidity-defichain-poolpair.strategy'; -import { PurchaseLiquidityDeFiChainStockStrategy } from '../purchase-liquidity/purchase-liquidity-defichain-stock.strategy'; -import { PurchaseLiquidityEthereumCryptoStrategy } from '../purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy'; -import { CheckLiquidityStrategyAlias, DexStrategiesFacade, PurchaseLiquidityStrategyAlias } from '../strategies.facade'; - -describe('DexStrategiesFacade', () => { - let nodeService: NodeService; - - let checkLiquidityDeFiChainPoolPairStrategy: CheckLiquidityDeFiChainPoolPairStrategy; - let checkLiquidityDeFiChainDefaultStrategy: CheckLiquidityDeFiChainDefaultStrategy; - let checkLiquidityEthereumStrategy: CheckLiquidityEthereumCryptoStrategy; - let checkLiquidityBSCStrategy: CheckLiquidityBscCryptoStrategy; - let purchaseLiquidityDeFiChainPoolPairStrategy: PurchaseLiquidityDeFiChainPoolPairStrategy; - let purchaseLiquidityDeFiChainStockStrategy: PurchaseLiquidityDeFiChainStockStrategy; - let purchaseLiquidityDeFiChainCryptoStrategy: PurchaseLiquidityDeFiChainCryptoStrategy; - let purchaseLiquidityEthereumStrategy: PurchaseLiquidityEthereumCryptoStrategy; - let purchaseLiquidityBscStrategy: PurchaseLiquidityBscCryptoStrategy; - - let facade: DexStrategiesFacadeWrapper; - - beforeEach(() => { - nodeService = mock(); - jest.spyOn(nodeService, 'getConnectedNode').mockImplementation(() => new BehaviorSubject(null)); - - checkLiquidityDeFiChainPoolPairStrategy = new CheckLiquidityDeFiChainPoolPairStrategy(); - checkLiquidityDeFiChainDefaultStrategy = new CheckLiquidityDeFiChainDefaultStrategy(mock()); - checkLiquidityEthereumStrategy = new CheckLiquidityEthereumCryptoStrategy(mock()); - checkLiquidityBSCStrategy = new CheckLiquidityBscCryptoStrategy(mock()); - purchaseLiquidityDeFiChainPoolPairStrategy = new PurchaseLiquidityDeFiChainPoolPairStrategy( - nodeService, - mock(), - mock(), - mock(), - mock(), - mock(), - mock(), - ); - purchaseLiquidityDeFiChainStockStrategy = new PurchaseLiquidityDeFiChainStockStrategy( - mock(), - mock(), - mock(), - mock(), - ); - purchaseLiquidityDeFiChainCryptoStrategy = new PurchaseLiquidityDeFiChainCryptoStrategy( - mock(), - mock(), - mock(), - mock(), - ); - purchaseLiquidityEthereumStrategy = new PurchaseLiquidityEthereumCryptoStrategy( - mock(), - mock(), - ); - purchaseLiquidityBscStrategy = new PurchaseLiquidityBscCryptoStrategy(mock(), mock()); - - facade = new DexStrategiesFacadeWrapper( - checkLiquidityDeFiChainPoolPairStrategy, - checkLiquidityDeFiChainDefaultStrategy, - checkLiquidityEthereumStrategy, - checkLiquidityBSCStrategy, - purchaseLiquidityDeFiChainPoolPairStrategy, - purchaseLiquidityDeFiChainStockStrategy, - purchaseLiquidityDeFiChainCryptoStrategy, - purchaseLiquidityEthereumStrategy, - purchaseLiquidityBscStrategy, - ); - }); - - describe('#constructor(...)', () => { - it('adds all checkLiquidityStrategies to a map', () => { - expect([...facade.getCheckLiquidityStrategies().entries()].length).toBe(4); - }); - - it('sets all required checkLiquidityStrategies aliases', () => { - const aliases = [...facade.getCheckLiquidityStrategies().keys()]; - - expect(aliases.includes(CheckLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR)).toBe(true); - expect(aliases.includes(CheckLiquidityStrategyAlias.DEFICHAIN_DEFAULT)).toBe(true); - expect(aliases.includes(CheckLiquidityStrategyAlias.ETHEREUM_DEFAULT)).toBe(true); - expect(aliases.includes(CheckLiquidityStrategyAlias.BSC_DEFAULT)).toBe(true); - }); - - it('assigns proper checkLiquidityStrategies to aliases', () => { - expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR)).toBeInstanceOf( - CheckLiquidityDeFiChainPoolPairStrategy, - ); - - expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityStrategyAlias.DEFICHAIN_DEFAULT)).toBeInstanceOf( - CheckLiquidityDeFiChainDefaultStrategy, - ); - - expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityStrategyAlias.ETHEREUM_DEFAULT)).toBeInstanceOf( - CheckLiquidityEthereumCryptoStrategy, - ); - - expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityStrategyAlias.BSC_DEFAULT)).toBeInstanceOf( - CheckLiquidityBscCryptoStrategy, - ); - }); - - it('adds all purchaseLiquidityStrategies to a map', () => { - expect([...facade.getPurchaseLiquidityStrategies().entries()].length).toBe(5); - }); - - it('sets all required purchaseLiquidityStrategies aliases', () => { - const aliases = [...facade.getPurchaseLiquidityStrategies().keys()]; - - expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR)).toBe(true); - expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK)).toBe(true); - expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO)).toBe(true); - expect(aliases.includes(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT)).toBe(true); - expect(aliases.includes(PurchaseLiquidityStrategyAlias.BSC_DEFAULT)).toBe(true); - }); - - it('assigns proper purchaseLiquidityStrategies to aliases', () => { - expect( - facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR), - ).toBeInstanceOf(PurchaseLiquidityDeFiChainPoolPairStrategy); - - expect( - facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK), - ).toBeInstanceOf(PurchaseLiquidityDeFiChainStockStrategy); - - expect( - facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO), - ).toBeInstanceOf(PurchaseLiquidityDeFiChainCryptoStrategy); - - expect( - facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT), - ).toBeInstanceOf(PurchaseLiquidityEthereumCryptoStrategy); - - expect(facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.BSC_DEFAULT)).toBeInstanceOf( - PurchaseLiquidityBscCryptoStrategy, - ); - }); - }); - - describe('#getCheckLiquidityStrategy(...)', () => { - describe('getting strategy by Asset', () => { - it('gets DEFICHAIN_POOL_PAIR strategy for DEFICHAIN', () => { - const strategy = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.POOL_PAIR }), - ); - - expect(strategy).toBeInstanceOf(CheckLiquidityDeFiChainPoolPairStrategy); - }); - - it('gets DEFICHAIN_DEFAULT strategy for DEFICHAIN', () => { - const strategyCrypto = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.CRYPTO }), - ); - - expect(strategyCrypto).toBeInstanceOf(CheckLiquidityDeFiChainDefaultStrategy); - - const strategyStock = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.STOCK }), - ); - - expect(strategyStock).toBeInstanceOf(CheckLiquidityDeFiChainDefaultStrategy); - }); - - it('gets DEFICHAIN_DEFAULT strategy for BITCOIN', () => { - const strategyCrypto = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BITCOIN, category: AssetCategory.CRYPTO }), - ); - - expect(strategyCrypto).toBeInstanceOf(CheckLiquidityDeFiChainDefaultStrategy); - - const strategyStock = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BITCOIN, category: AssetCategory.STOCK }), - ); - - expect(strategyStock).toBeInstanceOf(CheckLiquidityDeFiChainDefaultStrategy); - }); - - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getCheckLiquidityStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); - - expect(strategy).toBeInstanceOf(CheckLiquidityEthereumCryptoStrategy); - }); - - it('gets BSC_DEFAULT strategy', () => { - const strategy = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN }), - ); - - expect(strategy).toBeInstanceOf(CheckLiquidityBscCryptoStrategy); - }); - - it('fails to get strategy for non-supported Blockchain', () => { - const testCall = () => - facade.getCheckLiquidityStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No CheckLiquidityStrategy found. Alias: undefined'); - }); - }); - - describe('getting strategy by Alias', () => { - it('gets DEFICHAIN_POOL_PAIR strategy', () => { - const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR); - - expect(strategy).toBeInstanceOf(CheckLiquidityDeFiChainPoolPairStrategy); - }); - - it('gets DEFICHAIN_DEFAULT strategy', () => { - const strategyCrypto = facade.getCheckLiquidityStrategy(CheckLiquidityStrategyAlias.DEFICHAIN_DEFAULT); - - expect(strategyCrypto).toBeInstanceOf(CheckLiquidityDeFiChainDefaultStrategy); - }); - - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityStrategyAlias.ETHEREUM_DEFAULT); - - expect(strategy).toBeInstanceOf(CheckLiquidityEthereumCryptoStrategy); - }); - - it('gets BSC_DEFAULT strategy', () => { - const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityStrategyAlias.BSC_DEFAULT); - - expect(strategy).toBeInstanceOf(CheckLiquidityBscCryptoStrategy); - }); - - it('fails to get strategy for non-supported Alias', () => { - const testCall = () => facade.getCheckLiquidityStrategy('NonExistingAlias' as CheckLiquidityStrategyAlias); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No CheckLiquidityStrategy found. Alias: NonExistingAlias'); - }); - }); - }); - - describe('#getPurchaseLiquidityStrategy(...)', () => { - describe('getting strategy by Asset', () => { - it('gets DEFICHAIN_POOL_PAIR strategy for DEFICHAIN Pool Pair', () => { - const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.POOL_PAIR }), - ); - - expect(strategy).toBeInstanceOf(PurchaseLiquidityDeFiChainPoolPairStrategy); - }); - - it('gets DEFICHAIN_STOCK strategy for DEFICHAIN Stock', () => { - const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.STOCK }), - ); - - expect(strategy).toBeInstanceOf(PurchaseLiquidityDeFiChainStockStrategy); - }); - - it('gets DEFICHAIN_CRYPTO strategy for DEFICHAIN Crypto', () => { - const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.CRYPTO }), - ); - - expect(strategy).toBeInstanceOf(PurchaseLiquidityDeFiChainCryptoStrategy); - }); - - it('gets DEFICHAIN_CRYPTO strategy for BITCOIN Crypto', () => { - const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BITCOIN, category: AssetCategory.CRYPTO }), - ); - - expect(strategy).toBeInstanceOf(PurchaseLiquidityDeFiChainCryptoStrategy); - }); - - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); - - expect(strategy).toBeInstanceOf(PurchaseLiquidityEthereumCryptoStrategy); - }); - - it('gets BSC_DEFAULT strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN }), - ); - - expect(strategy).toBeInstanceOf(PurchaseLiquidityBscCryptoStrategy); - }); - - it('fails to get strategy for non-supported Blockchain', () => { - const testCall = () => - facade.getPurchaseLiquidityStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PurchaseLiquidityStrategy found. Alias: undefined'); - }); - - it('fails to get strategy for non-supported AssetCategory', () => { - const testCall = () => - facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: 'NewCategory' as AssetCategory }), - ); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PurchaseLiquidityStrategy found. Alias: undefined'); - }); - }); - - describe('getting strategy by Alias', () => { - it('gets DEFICHAIN_POOL_PAIR strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR); - - expect(strategy).toBeInstanceOf(PurchaseLiquidityDeFiChainPoolPairStrategy); - }); - - it('gets DEFICHAIN_STOCK strategy', () => { - const strategyCrypto = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK); - - expect(strategyCrypto).toBeInstanceOf(PurchaseLiquidityDeFiChainStockStrategy); - }); - - it('gets DEFICHAIN_CRYPTO strategy', () => { - const strategyCrypto = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO); - - expect(strategyCrypto).toBeInstanceOf(PurchaseLiquidityDeFiChainCryptoStrategy); - }); - - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT); - - expect(strategy).toBeInstanceOf(PurchaseLiquidityEthereumCryptoStrategy); - }); - - it('gets BSC_DEFAULT strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.BSC_DEFAULT); - - expect(strategy).toBeInstanceOf(PurchaseLiquidityBscCryptoStrategy); - }); - - it('fails to get strategy for non-supported Alias', () => { - const testCall = () => - facade.getPurchaseLiquidityStrategy('NonExistingAlias' as PurchaseLiquidityStrategyAlias); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PurchaseLiquidityStrategy found. Alias: NonExistingAlias'); - }); - }); - }); -}); - -class DexStrategiesFacadeWrapper extends DexStrategiesFacade { - constructor( - checkLiquidityDeFiChainPoolPairStrategy: CheckLiquidityDeFiChainPoolPairStrategy, - checkLiquidityDeFiChainDefaultStrategy: CheckLiquidityDeFiChainDefaultStrategy, - checkLiquidityEthereumStrategy: CheckLiquidityEthereumCryptoStrategy, - checkLiquidityBSCStrategy: CheckLiquidityBscCryptoStrategy, - purchaseLiquidityDeFiChainPoolPairStrategy: PurchaseLiquidityDeFiChainPoolPairStrategy, - purchaseLiquidityDeFiChainStockStrategy: PurchaseLiquidityDeFiChainStockStrategy, - purchaseLiquidityDeFiChainCryptoStrategy: PurchaseLiquidityDeFiChainCryptoStrategy, - purchaseLiquidityEthereumStrategy: PurchaseLiquidityEthereumCryptoStrategy, - purchaseLiquidityBSCStrategy: PurchaseLiquidityBscCryptoStrategy, - ) { - super( - checkLiquidityDeFiChainPoolPairStrategy, - checkLiquidityDeFiChainDefaultStrategy, - checkLiquidityEthereumStrategy, - checkLiquidityBSCStrategy, - purchaseLiquidityDeFiChainPoolPairStrategy, - purchaseLiquidityDeFiChainStockStrategy, - purchaseLiquidityDeFiChainCryptoStrategy, - purchaseLiquidityEthereumStrategy, - purchaseLiquidityBSCStrategy, - ); - } - - getCheckLiquidityStrategies() { - return this.checkLiquidityStrategies; - } - - getPurchaseLiquidityStrategies() { - return this.purchaseLiquidityStrategies; - } -} diff --git a/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts b/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts new file mode 100644 index 0000000000..d893f1995c --- /dev/null +++ b/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts @@ -0,0 +1,187 @@ +import { mock } from 'jest-mock-extended'; +import { BehaviorSubject } from 'rxjs'; +import { NodeService } from 'src/blockchain/ain/node/node.service'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { AssetCategory } from 'src/shared/models/asset/asset.entity'; +import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; +import { DexBscService } from '../../../services/dex-bsc.service'; +import { DexDeFiChainService } from '../../../services/dex-defichain.service'; +import { DexEthereumService } from '../../../services/dex-ethereum.service'; +import { CheckLiquidityStrategies } from '../check-liquidity.facade'; +import { BscCryptoStrategy } from '../impl/bsc-crypto.strategy'; +import { DeFiChainDefaultStrategy } from '../impl/defichain-default.strategy'; +import { DeFiChainPoolPairStrategy } from '../impl/defichain-poolpair.strategy'; +import { EthereumCryptoStrategy } from '../impl/ethereum-crypto.strategy'; +import { CheckLiquidityAlias } from '../check-liquidity.facade'; + +describe('CheckLiquidityStrategies', () => { + let nodeService: NodeService; + + let deFiChainPoolPair: DeFiChainPoolPairStrategy; + let deFiChainDefault: DeFiChainDefaultStrategy; + let ethereum: EthereumCryptoStrategy; + let bsc: BscCryptoStrategy; + + let facade: CheckLiquidityStrategiesWrapper; + + beforeEach(() => { + nodeService = mock(); + jest.spyOn(nodeService, 'getConnectedNode').mockImplementation(() => new BehaviorSubject(null)); + + deFiChainPoolPair = new DeFiChainPoolPairStrategy(); + deFiChainDefault = new DeFiChainDefaultStrategy(mock()); + ethereum = new EthereumCryptoStrategy(mock()); + bsc = new BscCryptoStrategy(mock()); + + facade = new CheckLiquidityStrategiesWrapper(deFiChainPoolPair, deFiChainDefault, ethereum, bsc); + }); + + describe('#constructor(...)', () => { + it('adds all checkLiquidityStrategies to a map', () => { + expect([...facade.getCheckLiquidityStrategies().entries()].length).toBe(4); + }); + + it('sets all required checkLiquidityStrategies aliases', () => { + const aliases = [...facade.getCheckLiquidityStrategies().keys()]; + + expect(aliases.includes(CheckLiquidityAlias.DEFICHAIN_POOL_PAIR)).toBe(true); + expect(aliases.includes(CheckLiquidityAlias.DEFICHAIN_DEFAULT)).toBe(true); + expect(aliases.includes(CheckLiquidityAlias.ETHEREUM_DEFAULT)).toBe(true); + expect(aliases.includes(CheckLiquidityAlias.BSC_DEFAULT)).toBe(true); + }); + + it('assigns proper checkLiquidityStrategies to aliases', () => { + expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityAlias.DEFICHAIN_POOL_PAIR)).toBeInstanceOf( + DeFiChainPoolPairStrategy, + ); + + expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityAlias.DEFICHAIN_DEFAULT)).toBeInstanceOf( + DeFiChainDefaultStrategy, + ); + + expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityAlias.ETHEREUM_DEFAULT)).toBeInstanceOf( + EthereumCryptoStrategy, + ); + + expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityAlias.BSC_DEFAULT)).toBeInstanceOf( + BscCryptoStrategy, + ); + }); + }); + + describe('#getCheckLiquidityStrategy(...)', () => { + describe('getting strategy by Asset', () => { + it('gets DEFICHAIN_POOL_PAIR strategy for DEFICHAIN', () => { + const strategy = facade.getCheckLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.POOL_PAIR }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainPoolPairStrategy); + }); + + it('gets DEFICHAIN_DEFAULT strategy for DEFICHAIN', () => { + const strategyCrypto = facade.getCheckLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.CRYPTO }), + ); + + expect(strategyCrypto).toBeInstanceOf(DeFiChainDefaultStrategy); + + const strategyStock = facade.getCheckLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.STOCK }), + ); + + expect(strategyStock).toBeInstanceOf(DeFiChainDefaultStrategy); + }); + + it('gets DEFICHAIN_DEFAULT strategy for BITCOIN', () => { + const strategyCrypto = facade.getCheckLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.BITCOIN, category: AssetCategory.CRYPTO }), + ); + + expect(strategyCrypto).toBeInstanceOf(DeFiChainDefaultStrategy); + + const strategyStock = facade.getCheckLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.BITCOIN, category: AssetCategory.STOCK }), + ); + + expect(strategyStock).toBeInstanceOf(DeFiChainDefaultStrategy); + }); + + it('gets ETHEREUM_DEFAULT strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); + + expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + }); + + it('gets BSC_DEFAULT strategy', () => { + const strategy = facade.getCheckLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN }), + ); + + expect(strategy).toBeInstanceOf(BscCryptoStrategy); + }); + + it('fails to get strategy for non-supported Blockchain', () => { + const testCall = () => + facade.getCheckLiquidityStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No CheckLiquidityStrategy found. Alias: undefined'); + }); + }); + + describe('getting strategy by CheckLiquidityAlias', () => { + it('gets DEFICHAIN_POOL_PAIR strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.DEFICHAIN_POOL_PAIR); + + expect(strategy).toBeInstanceOf(DeFiChainPoolPairStrategy); + }); + + it('gets DEFICHAIN_DEFAULT strategy', () => { + const strategyCrypto = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.DEFICHAIN_DEFAULT); + + expect(strategyCrypto).toBeInstanceOf(DeFiChainDefaultStrategy); + }); + + it('gets ETHEREUM_DEFAULT strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.ETHEREUM_DEFAULT); + + expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + }); + + it('gets BSC_DEFAULT strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.BSC_DEFAULT); + + expect(strategy).toBeInstanceOf(BscCryptoStrategy); + }); + + it('fails to get strategy for non-supported CheckLiquidityAlias', () => { + const testCall = () => + facade.getCheckLiquidityStrategy('NonExistingCheckLiquidityAlias' as CheckLiquidityAlias); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No CheckLiquidityStrategy found. Alias: NonExistingCheckLiquidityAlias'); + }); + }); + }); +}); + +class CheckLiquidityStrategiesWrapper extends CheckLiquidityStrategies { + constructor( + checkLiquidityDeFiChainPoolPairStrategy: DeFiChainPoolPairStrategy, + checkLiquidityDeFiChainDefaultStrategy: DeFiChainDefaultStrategy, + checkLiquidityEthereumStrategy: EthereumCryptoStrategy, + checkLiquidityBSCStrategy: BscCryptoStrategy, + ) { + super( + checkLiquidityDeFiChainPoolPairStrategy, + checkLiquidityDeFiChainDefaultStrategy, + checkLiquidityEthereumStrategy, + checkLiquidityBSCStrategy, + ); + } + + getCheckLiquidityStrategies() { + return this.strategies; + } +} diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-crypto.strategy.ts deleted file mode 100644 index e227b1782e..0000000000 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-crypto.strategy.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { DexBscService } from '../../services/dex-bsc.service'; -import { CheckLiquidityEvmCryptoStrategy } from './base/check-liquidity-evm-crypto.strategy'; - -@Injectable() -export class CheckLiquidityBscCryptoStrategy extends CheckLiquidityEvmCryptoStrategy { - constructor(dexBscService: DexBscService) { - super(dexBscService); - } -} diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-token.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-token.strategy.ts deleted file mode 100644 index 511c0a8333..0000000000 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bsc-token.strategy.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { DexBscService } from '../../services/dex-bsc.service'; -import { CheckLiquidityEvmTokenStrategy } from './base/check-liquidity-evm-token.strategy'; - -@Injectable() -export class CheckLiquidityBscTokenStrategy extends CheckLiquidityEvmTokenStrategy { - constructor(dexBscService: DexBscService) { - super(dexBscService); - } -} diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-crypto.strategy.ts deleted file mode 100644 index 406449c239..0000000000 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-crypto.strategy.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { DexEthereumService } from '../../services/dex-ethereum.service'; -import { CheckLiquidityEvmCryptoStrategy } from './base/check-liquidity-evm-crypto.strategy'; - -@Injectable() -export class CheckLiquidityEthereumCryptoStrategy extends CheckLiquidityEvmCryptoStrategy { - constructor(dexEthereumService: DexEthereumService) { - super(dexEthereumService); - } -} diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-token.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-token.strategy.ts deleted file mode 100644 index 387c43fb71..0000000000 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-ethereum-token.strategy.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { DexEthereumService } from '../../services/dex-ethereum.service'; -import { CheckLiquidityEvmTokenStrategy } from './base/check-liquidity-evm-token.strategy'; - -@Injectable() -export class CheckLiquidityEthereumTokenStrategy extends CheckLiquidityEvmTokenStrategy { - constructor(dexEthereumService: DexEthereumService) { - super(dexEthereumService); - } -} diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts new file mode 100644 index 0000000000..f618ec7f76 --- /dev/null +++ b/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts @@ -0,0 +1,68 @@ +import { Injectable } from '@nestjs/common'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { Asset, AssetCategory } from 'src/shared/models/asset/asset.entity'; +import { CheckLiquidityStrategy } from './impl/base/check-liquidity.strategy'; +import { BscCryptoStrategy } from './impl/bsc-crypto.strategy'; +import { DeFiChainDefaultStrategy } from './impl/defichain-default.strategy'; +import { DeFiChainPoolPairStrategy } from './impl/defichain-poolpair.strategy'; +import { EthereumCryptoStrategy } from './impl/ethereum-crypto.strategy'; + +enum Alias { + DEFICHAIN_POOL_PAIR = 'DeFiChainPoolPair', + DEFICHAIN_DEFAULT = 'DeFiChainDefault', + ETHEREUM_DEFAULT = 'EthereumDefault', + BSC_DEFAULT = 'BscDefault', +} + +export { Alias as CheckLiquidityAlias }; + +@Injectable() +export class CheckLiquidityStrategies { + protected readonly strategies = new Map(); + + constructor( + deFiChainPoolPair: DeFiChainPoolPairStrategy, + deFiChainDefault: DeFiChainDefaultStrategy, + ethereum: EthereumCryptoStrategy, + bsc: BscCryptoStrategy, + ) { + this.strategies.set(Alias.DEFICHAIN_POOL_PAIR, deFiChainPoolPair); + this.strategies.set(Alias.DEFICHAIN_DEFAULT, deFiChainDefault); + this.strategies.set(Alias.ETHEREUM_DEFAULT, ethereum); + this.strategies.set(Alias.BSC_DEFAULT, bsc); + } + + getCheckLiquidityStrategy(criteria: Asset | Alias): CheckLiquidityStrategy { + return criteria instanceof Asset + ? this.getCheckLiquidityStrategyByAsset(criteria) + : this.getCheckLiquidityStrategyByAlias(criteria); + } + + //*** HELPER METHODS ***// + + private getCheckLiquidityStrategyByAlias(alias: Alias): CheckLiquidityStrategy { + const strategy = this.strategies.get(alias); + + if (!strategy) throw new Error(`No CheckLiquidityStrategy found. Alias: ${alias}`); + + return strategy; + } + + private getCheckLiquidityStrategyByAsset(asset: Asset): CheckLiquidityStrategy { + const alias = this.getAlias(asset); + + return this.getCheckLiquidityStrategyByAlias(alias); + } + + private getAlias(asset: Asset): Alias { + const { blockchain, category: assetCategory } = asset; + + if (blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) { + if (assetCategory === AssetCategory.POOL_PAIR) return Alias.DEFICHAIN_POOL_PAIR; + return Alias.DEFICHAIN_DEFAULT; + } + + if (blockchain === Blockchain.ETHEREUM) return Alias.ETHEREUM_DEFAULT; + if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return Alias.BSC_DEFAULT; + } +} diff --git a/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/base/check-liquidity.strategy.ts similarity index 64% rename from src/payment/models/dex/strategies/check-liquidity/base/check-liquidity.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/impl/base/check-liquidity.strategy.ts index b618e63130..600a01de70 100644 --- a/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/base/check-liquidity.strategy.ts @@ -1,4 +1,4 @@ -import { LiquidityRequest } from '../../../interfaces'; +import { LiquidityRequest } from '../../../../interfaces'; export interface CheckLiquidityStrategy { checkLiquidity(request: LiquidityRequest): Promise; diff --git a/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-crypto.strategy.ts similarity index 63% rename from src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-crypto.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/impl/base/evm-crypto.strategy.ts index b1683bb10d..562e4302c6 100644 --- a/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-crypto.strategy.ts @@ -1,8 +1,8 @@ -import { LiquidityRequest } from '../../../interfaces'; -import { DexEvmService } from '../../../services/dex-evm.service'; +import { LiquidityRequest } from '../../../../interfaces'; +import { DexEvmService } from '../../../../services/dex-evm.service'; import { CheckLiquidityStrategy } from './check-liquidity.strategy'; -export class CheckLiquidityEvmCryptoStrategy implements CheckLiquidityStrategy { +export class EvmCryptoStrategy implements CheckLiquidityStrategy { constructor(protected readonly dexEvmService: DexEvmService) {} async checkLiquidity(request: LiquidityRequest): Promise { diff --git a/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-token.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts similarity index 52% rename from src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-token.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts index 6906139d18..61a9e01252 100644 --- a/src/payment/models/dex/strategies/check-liquidity/base/check-liquidity-evm-token.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts @@ -1,8 +1,8 @@ -import { LiquidityRequest } from '../../../interfaces'; -import { DexEvmService } from '../../../services/dex-evm.service'; +import { LiquidityRequest } from '../../../../interfaces'; +import { DexEvmService } from '../../../../services/dex-evm.service'; import { CheckLiquidityStrategy } from './check-liquidity.strategy'; -export class CheckLiquidityEvmTokenStrategy implements CheckLiquidityStrategy { +export class EvmTokenStrategy implements CheckLiquidityStrategy { constructor(protected readonly dexEvmService: DexEvmService) {} async checkLiquidity(request: LiquidityRequest): Promise { diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bitcoin.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/bitcoin.strategy.ts similarity index 58% rename from src/payment/models/dex/strategies/check-liquidity/check-liquidity-bitcoin.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/impl/bitcoin.strategy.ts index 18808bde41..305ab3629e 100644 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-bitcoin.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/bitcoin.strategy.ts @@ -1,10 +1,10 @@ import { Injectable } from '@nestjs/common'; -import { LiquidityRequest } from '../../interfaces'; -import { DexBitcoinService } from '../../services/dex-bitcoin.service'; +import { LiquidityRequest } from '../../../interfaces'; +import { DexBitcoinService } from '../../../services/dex-bitcoin.service'; import { CheckLiquidityStrategy } from './base/check-liquidity.strategy'; @Injectable() -export class CheckLiquidityBitcoinStrategy implements CheckLiquidityStrategy { +export class BitcoinStrategy implements CheckLiquidityStrategy { constructor(private readonly dexBtcService: DexBitcoinService) {} async checkLiquidity(request: LiquidityRequest): Promise { diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/bsc-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/bsc-crypto.strategy.ts new file mode 100644 index 0000000000..263d677ce7 --- /dev/null +++ b/src/payment/models/dex/strategies/check-liquidity/impl/bsc-crypto.strategy.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { DexBscService } from '../../../services/dex-bsc.service'; +import { EvmCryptoStrategy } from './base/evm-crypto.strategy'; + +@Injectable() +export class BscCryptoStrategy extends EvmCryptoStrategy { + constructor(dexBscService: DexBscService) { + super(dexBscService); + } +} diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/bsc-token.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/bsc-token.strategy.ts new file mode 100644 index 0000000000..31c82a3c9c --- /dev/null +++ b/src/payment/models/dex/strategies/check-liquidity/impl/bsc-token.strategy.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { DexBscService } from '../../../services/dex-bsc.service'; +import { EvmTokenStrategy } from './base/evm-token.strategy'; + +@Injectable() +export class BscTokenStrategy extends EvmTokenStrategy { + constructor(dexBscService: DexBscService) { + super(dexBscService); + } +} diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-defichain-default.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/defichain-default.strategy.ts similarity index 69% rename from src/payment/models/dex/strategies/check-liquidity/check-liquidity-defichain-default.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/impl/defichain-default.strategy.ts index d7cd3177ba..19f84e3081 100644 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-defichain-default.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/defichain-default.strategy.ts @@ -1,11 +1,11 @@ import { Injectable } from '@nestjs/common'; -import { LiquidityOrder } from '../../entities/liquidity-order.entity'; -import { LiquidityRequest } from '../../interfaces'; -import { DexDeFiChainService } from '../../services/dex-defichain.service'; +import { LiquidityOrder } from '../../../entities/liquidity-order.entity'; +import { LiquidityRequest } from '../../../interfaces'; +import { DexDeFiChainService } from '../../../services/dex-defichain.service'; import { CheckLiquidityStrategy } from './base/check-liquidity.strategy'; @Injectable() -export class CheckLiquidityDeFiChainDefaultStrategy implements CheckLiquidityStrategy { +export class DeFiChainDefaultStrategy implements CheckLiquidityStrategy { constructor(private readonly dexDeFiChainService: DexDeFiChainService) {} async checkLiquidity(request: LiquidityRequest): Promise { diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-defichain-poolpair.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/defichain-poolpair.strategy.ts similarity index 74% rename from src/payment/models/dex/strategies/check-liquidity/check-liquidity-defichain-poolpair.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/impl/defichain-poolpair.strategy.ts index 8049d4cdbb..cf1b6407a8 100644 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity-defichain-poolpair.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/defichain-poolpair.strategy.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { CheckLiquidityStrategy } from './base/check-liquidity.strategy'; @Injectable() -export class CheckLiquidityDeFiChainPoolPairStrategy implements CheckLiquidityStrategy { +export class DeFiChainPoolPairStrategy implements CheckLiquidityStrategy { // assume there is no poolpair liquidity available on DEX node async checkLiquidity(): Promise { return 0; diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/ethereum-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/ethereum-crypto.strategy.ts new file mode 100644 index 0000000000..b2899ee33e --- /dev/null +++ b/src/payment/models/dex/strategies/check-liquidity/impl/ethereum-crypto.strategy.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { DexEthereumService } from '../../../services/dex-ethereum.service'; +import { EvmCryptoStrategy } from './base/evm-crypto.strategy'; + +@Injectable() +export class EthereumCryptoStrategy extends EvmCryptoStrategy { + constructor(dexEthereumService: DexEthereumService) { + super(dexEthereumService); + } +} diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/ethereum-token.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/ethereum-token.strategy.ts new file mode 100644 index 0000000000..55ee9d5635 --- /dev/null +++ b/src/payment/models/dex/strategies/check-liquidity/impl/ethereum-token.strategy.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { DexEthereumService } from '../../../services/dex-ethereum.service'; +import { EvmTokenStrategy } from './base/evm-token.strategy'; + +@Injectable() +export class EthereumTokenStrategy extends EvmTokenStrategy { + constructor(dexEthereumService: DexEthereumService) { + super(dexEthereumService); + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts b/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts new file mode 100644 index 0000000000..79d943c765 --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts @@ -0,0 +1,231 @@ +import { mock } from 'jest-mock-extended'; +import { BehaviorSubject } from 'rxjs'; +import { NodeService } from 'src/blockchain/ain/node/node.service'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { AssetCategory } from 'src/shared/models/asset/asset.entity'; +import { AssetService } from 'src/shared/models/asset/asset.service'; +import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; +import { SettingService } from 'src/shared/models/setting/setting.service'; +import { MailService } from 'src/shared/services/mail.service'; +import { LiquidityOrderFactory } from '../../../factories/liquidity-order.factory'; +import { LiquidityOrderRepository } from '../../../repositories/liquidity-order.repository'; +import { DexBscService } from '../../../services/dex-bsc.service'; +import { DexDeFiChainService } from '../../../services/dex-defichain.service'; +import { DexService } from '../../../services/dex.service'; +import { BscCryptoStrategy } from '../impl/bsc-crypto.strategy'; +import { DeFiChainCryptoStrategy } from '../impl/defichain-crypto.strategy'; +import { DeFiChainPoolPairStrategy } from '../impl/defichain-poolpair.strategy'; +import { DeFiChainStockStrategy } from '../impl/defichain-stock.strategy'; +import { EthereumCryptoStrategy } from '../impl/ethereum-crypto.strategy'; +import { PurchaseLiquidityStrategyAlias, PurchaseLiquidityStrategies } from '../purchase-liquidity.facade'; + +describe('PurchaseLiquidityStrategies', () => { + let nodeService: NodeService; + + let deFiChainPoolPair: DeFiChainPoolPairStrategy; + let deFiChainStock: DeFiChainStockStrategy; + let deFiChainCrypto: DeFiChainCryptoStrategy; + let ethereum: EthereumCryptoStrategy; + let bsc: BscCryptoStrategy; + + let facade: PurchaseLiquidityStrategiesWrapper; + + beforeEach(() => { + nodeService = mock(); + jest.spyOn(nodeService, 'getConnectedNode').mockImplementation(() => new BehaviorSubject(null)); + + deFiChainPoolPair = new DeFiChainPoolPairStrategy( + nodeService, + mock(), + mock(), + mock(), + mock(), + mock(), + mock(), + ); + deFiChainStock = new DeFiChainStockStrategy( + mock(), + mock(), + mock(), + mock(), + ); + deFiChainCrypto = new DeFiChainCryptoStrategy( + mock(), + mock(), + mock(), + mock(), + ); + ethereum = new EthereumCryptoStrategy(mock(), mock()); + bsc = new BscCryptoStrategy(mock(), mock()); + + facade = new PurchaseLiquidityStrategiesWrapper(deFiChainPoolPair, deFiChainStock, deFiChainCrypto, ethereum, bsc); + }); + + describe('#constructor(...)', () => { + it('adds all purchaseLiquidityStrategies to a map', () => { + expect([...facade.getPurchaseLiquidityStrategies().entries()].length).toBe(5); + }); + + it('sets all required purchaseLiquidityStrategies aliases', () => { + const aliases = [...facade.getPurchaseLiquidityStrategies().keys()]; + + expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR)).toBe(true); + expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK)).toBe(true); + expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO)).toBe(true); + expect(aliases.includes(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT)).toBe(true); + expect(aliases.includes(PurchaseLiquidityStrategyAlias.BSC_DEFAULT)).toBe(true); + }); + + it('assigns proper purchaseLiquidityStrategies to aliases', () => { + expect( + facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR), + ).toBeInstanceOf(DeFiChainPoolPairStrategy); + + expect( + facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK), + ).toBeInstanceOf(DeFiChainStockStrategy); + + expect( + facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO), + ).toBeInstanceOf(DeFiChainCryptoStrategy); + + expect( + facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT), + ).toBeInstanceOf(EthereumCryptoStrategy); + + expect(facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.BSC_DEFAULT)).toBeInstanceOf( + BscCryptoStrategy, + ); + }); + }); + + describe('#getPurchaseLiquidityStrategy(...)', () => { + describe('getting strategy by Asset', () => { + it('gets DEFICHAIN_POOL_PAIR strategy for DEFICHAIN Pool Pair', () => { + const strategy = facade.getPurchaseLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.POOL_PAIR }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainPoolPairStrategy); + }); + + it('gets DEFICHAIN_STOCK strategy for DEFICHAIN Stock', () => { + const strategy = facade.getPurchaseLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.STOCK }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainStockStrategy); + }); + + it('gets DEFICHAIN_CRYPTO strategy for DEFICHAIN Crypto', () => { + const strategy = facade.getPurchaseLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.CRYPTO }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainCryptoStrategy); + }); + + it('gets DEFICHAIN_CRYPTO strategy for BITCOIN Crypto', () => { + const strategy = facade.getPurchaseLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.BITCOIN, category: AssetCategory.CRYPTO }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainCryptoStrategy); + }); + + it('gets ETHEREUM_DEFAULT strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); + + expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + }); + + it('gets BSC_DEFAULT strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN }), + ); + + expect(strategy).toBeInstanceOf(BscCryptoStrategy); + }); + + it('fails to get strategy for non-supported Blockchain', () => { + const testCall = () => + facade.getPurchaseLiquidityStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No PurchaseLiquidityStrategy found. Alias: undefined'); + }); + + it('fails to get strategy for non-supported AssetCategory', () => { + const testCall = () => + facade.getPurchaseLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: 'NewCategory' as AssetCategory }), + ); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No PurchaseLiquidityStrategy found. Alias: undefined'); + }); + }); + + describe('getting strategy by Alias', () => { + it('gets DEFICHAIN_POOL_PAIR strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR); + + expect(strategy).toBeInstanceOf(DeFiChainPoolPairStrategy); + }); + + it('gets DEFICHAIN_STOCK strategy', () => { + const strategyCrypto = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK); + + expect(strategyCrypto).toBeInstanceOf(DeFiChainStockStrategy); + }); + + it('gets DEFICHAIN_CRYPTO strategy', () => { + const strategyCrypto = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO); + + expect(strategyCrypto).toBeInstanceOf(DeFiChainCryptoStrategy); + }); + + it('gets ETHEREUM_DEFAULT strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT); + + expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + }); + + it('gets BSC_DEFAULT strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.BSC_DEFAULT); + + expect(strategy).toBeInstanceOf(BscCryptoStrategy); + }); + + it('fails to get strategy for non-supported Alias', () => { + const testCall = () => + facade.getPurchaseLiquidityStrategy('NonExistingAlias' as PurchaseLiquidityStrategyAlias); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No PurchaseLiquidityStrategy found. Alias: NonExistingAlias'); + }); + }); + }); +}); + +class PurchaseLiquidityStrategiesWrapper extends PurchaseLiquidityStrategies { + constructor( + purchaseLiquidityDeFiChainPoolPairStrategy: DeFiChainPoolPairStrategy, + purchaseLiquidityDeFiChainStockStrategy: DeFiChainStockStrategy, + purchaseLiquidityDeFiChainCryptoStrategy: DeFiChainCryptoStrategy, + purchaseLiquidityEthereumStrategy: EthereumCryptoStrategy, + purchaseLiquidityBSCStrategy: BscCryptoStrategy, + ) { + super( + purchaseLiquidityDeFiChainPoolPairStrategy, + purchaseLiquidityDeFiChainStockStrategy, + purchaseLiquidityDeFiChainCryptoStrategy, + purchaseLiquidityEthereumStrategy, + purchaseLiquidityBSCStrategy, + ); + } + + getPurchaseLiquidityStrategies() { + return this.purchaseLiquidityStrategies; + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-defichain-non-poolpair.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/defichain-non-poolpair.strategy.ts similarity index 82% rename from src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-defichain-non-poolpair.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/impl/base/defichain-non-poolpair.strategy.ts index a4de5d540b..fd68edb1c9 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-defichain-non-poolpair.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/defichain-non-poolpair.strategy.ts @@ -1,15 +1,15 @@ import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; import { AssetCategory } from 'src/shared/models/asset/asset.entity'; import { MailService } from 'src/shared/services/mail.service'; -import { LiquidityOrder } from '../../../entities/liquidity-order.entity'; -import { NotEnoughLiquidityException } from '../../../exceptions/not-enough-liquidity.exception'; -import { LiquidityOrderFactory } from '../../../factories/liquidity-order.factory'; -import { LiquidityRequest } from '../../../interfaces'; -import { LiquidityOrderRepository } from '../../../repositories/liquidity-order.repository'; -import { DexDeFiChainService } from '../../../services/dex-defichain.service'; +import { LiquidityOrder } from '../../../../entities/liquidity-order.entity'; +import { NotEnoughLiquidityException } from '../../../../exceptions/not-enough-liquidity.exception'; +import { LiquidityOrderFactory } from '../../../../factories/liquidity-order.factory'; +import { LiquidityRequest } from '../../../../interfaces'; +import { LiquidityOrderRepository } from '../../../../repositories/liquidity-order.repository'; +import { DexDeFiChainService } from '../../../../services/dex-defichain.service'; import { PurchaseLiquidityStrategy } from './purchase-liquidity.strategy'; -export abstract class PurchaseLiquidityDeFiChainNonPoolPairStrategy extends PurchaseLiquidityStrategy { +export abstract class DeFiChainNonPoolPairStrategy extends PurchaseLiquidityStrategy { private prioritySwapAssets: string[] = []; constructor( diff --git a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts similarity index 86% rename from src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-crypto.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts index a4116dea49..99921172e2 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts @@ -1,9 +1,9 @@ import { MailService } from 'src/shared/services/mail.service'; -import { LiquidityRequest } from '../../../interfaces'; -import { DexEvmService } from '../../../services/dex-evm.service'; +import { LiquidityRequest } from '../../../../interfaces'; +import { DexEvmService } from '../../../../services/dex-evm.service'; import { PurchaseLiquidityStrategy } from './purchase-liquidity.strategy'; -export class PurchaseLiquidityEvmCryptoStrategy extends PurchaseLiquidityStrategy { +export class EvmCryptoStrategy extends PurchaseLiquidityStrategy { constructor(mailService: MailService, protected readonly dexEvmService: DexEvmService) { super(mailService); } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-token.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts similarity index 62% rename from src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-token.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts index e693e62f72..50cc591718 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity-evm-token.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts @@ -1,9 +1,9 @@ import { MailService } from 'src/shared/services/mail.service'; -import { LiquidityRequest } from '../../../interfaces'; -import { DexEvmService } from '../../../services/dex-evm.service'; +import { LiquidityRequest } from '../../../../interfaces'; +import { DexEvmService } from '../../../../services/dex-evm.service'; import { PurchaseLiquidityStrategy } from './purchase-liquidity.strategy'; -export class PurchaseLiquidityEvmTokenStrategy extends PurchaseLiquidityStrategy { +export class EvmTokenStrategy extends PurchaseLiquidityStrategy { constructor(mailService: MailService, protected readonly dexEvmService: DexEvmService) { super(mailService); } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/purchase-liquidity.strategy.ts similarity index 75% rename from src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/impl/base/purchase-liquidity.strategy.ts index eb7c901319..1a09e83d46 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/base/purchase-liquidity.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/purchase-liquidity.strategy.ts @@ -1,7 +1,7 @@ import { MailService } from 'src/shared/services/mail.service'; -import { NotEnoughLiquidityException } from '../../../exceptions/not-enough-liquidity.exception'; -import { PriceSlippageException } from '../../../exceptions/price-slippage.exception'; -import { LiquidityRequest } from '../../../interfaces'; +import { NotEnoughLiquidityException } from '../../../../exceptions/not-enough-liquidity.exception'; +import { PriceSlippageException } from '../../../../exceptions/price-slippage.exception'; +import { LiquidityRequest } from '../../../../interfaces'; export abstract class PurchaseLiquidityStrategy { constructor(protected readonly mailService: MailService) {} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bitcoin.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/bitcoin.strategy.ts similarity index 62% rename from src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bitcoin.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/impl/bitcoin.strategy.ts index 243e59bec5..dea7b6b717 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bitcoin.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/bitcoin.strategy.ts @@ -1,9 +1,9 @@ import { Injectable } from '@nestjs/common'; import { PurchaseLiquidityStrategy } from './base/purchase-liquidity.strategy'; -import { LiquidityRequest } from '../../interfaces'; +import { LiquidityRequest } from '../../../interfaces'; @Injectable() -export class PurchaseLiquidityBitcoinStrategy extends PurchaseLiquidityStrategy { +export class BitcoinStrategy extends PurchaseLiquidityStrategy { async purchaseLiquidity(request: LiquidityRequest): Promise { return; } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-crypto.strategy.ts new file mode 100644 index 0000000000..f8665deaf9 --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-crypto.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { MailService } from 'src/shared/services/mail.service'; +import { DexBscService } from '../../../services/dex-bsc.service'; +import { EvmCryptoStrategy } from './base/evm-crypto.strategy'; + +@Injectable() +export class BscCryptoStrategy extends EvmCryptoStrategy { + constructor(mailService: MailService, dexBscService: DexBscService) { + super(mailService, dexBscService); + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-token.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-token.strategy.ts new file mode 100644 index 0000000000..5355c3d1b2 --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-token.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { MailService } from 'src/shared/services/mail.service'; +import { DexBscService } from '../../../services/dex-bsc.service'; +import { EvmTokenStrategy } from './base/evm-token.strategy'; + +@Injectable() +export class BscTokenStrategy extends EvmTokenStrategy { + constructor(mailService: MailService, dexBscService: DexBscService) { + super(mailService, dexBscService); + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-crypto.strategy.ts new file mode 100644 index 0000000000..461ee6a396 --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-crypto.strategy.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; +import { MailService } from 'src/shared/services/mail.service'; +import { LiquidityOrderFactory } from '../../../factories/liquidity-order.factory'; +import { LiquidityOrderRepository } from '../../../repositories/liquidity-order.repository'; +import { DexDeFiChainService } from '../../../services/dex-defichain.service'; +import { DeFiChainNonPoolPairStrategy } from './base/defichain-non-poolpair.strategy'; + +@Injectable() +export class DeFiChainCryptoStrategy extends DeFiChainNonPoolPairStrategy { + constructor( + readonly mailService: MailService, + readonly dexDeFiChainService: DexDeFiChainService, + readonly liquidityOrderRepo: LiquidityOrderRepository, + readonly liquidityOrderFactory: LiquidityOrderFactory, + ) { + super(mailService, dexDeFiChainService, liquidityOrderRepo, liquidityOrderFactory, ['DFI']); + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-poolpair.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-poolpair.strategy.ts similarity index 91% rename from src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-poolpair.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-poolpair.strategy.ts index 7d3799cc36..49ea4d07c0 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-poolpair.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-poolpair.strategy.ts @@ -6,22 +6,22 @@ import { Config } from 'src/config/config'; import { Asset, AssetCategory } from 'src/shared/models/asset/asset.entity'; import { AssetService } from 'src/shared/models/asset/asset.service'; import { MailService } from 'src/shared/services/mail.service'; -import { LiquidityOrder, LiquidityOrderContext } from '../../entities/liquidity-order.entity'; -import { LiquidityOrderFactory } from '../../factories/liquidity-order.factory'; -import { LiquidityOrderRepository } from '../../repositories/liquidity-order.repository'; -import { DexService } from '../../services/dex.service'; -import { PurchaseLiquidityStrategy } from './base/purchase-liquidity.strategy'; import { Util } from 'src/shared/util'; import { Lock } from 'src/shared/lock'; -import { NotEnoughLiquidityException } from '../../exceptions/not-enough-liquidity.exception'; -import { PriceSlippageException } from '../../exceptions/price-slippage.exception'; import { SettingService } from 'src/shared/models/setting/setting.service'; import { NodeService, NodeType } from 'src/blockchain/ain/node/node.service'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { LiquidityRequest } from '../../interfaces'; +import { LiquidityOrderContext, LiquidityOrder } from '../../../entities/liquidity-order.entity'; +import { NotEnoughLiquidityException } from '../../../exceptions/not-enough-liquidity.exception'; +import { PriceSlippageException } from '../../../exceptions/price-slippage.exception'; +import { LiquidityOrderFactory } from '../../../factories/liquidity-order.factory'; +import { LiquidityRequest } from '../../../interfaces'; +import { LiquidityOrderRepository } from '../../../repositories/liquidity-order.repository'; +import { DexService } from '../../../services/dex.service'; +import { PurchaseLiquidityStrategy } from './base/purchase-liquidity.strategy'; @Injectable() -export class PurchaseLiquidityDeFiChainPoolPairStrategy extends PurchaseLiquidityStrategy { +export class DeFiChainPoolPairStrategy extends PurchaseLiquidityStrategy { private readonly verifyDerivedOrdersLock = new Lock(1800); private chainClient: DeFiClient; diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-stock.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-stock.strategy.ts new file mode 100644 index 0000000000..5b157b920c --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/defichain-stock.strategy.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; +import { MailService } from 'src/shared/services/mail.service'; +import { LiquidityOrderFactory } from '../../../factories/liquidity-order.factory'; +import { LiquidityOrderRepository } from '../../../repositories/liquidity-order.repository'; +import { DexDeFiChainService } from '../../../services/dex-defichain.service'; +import { DeFiChainNonPoolPairStrategy } from './base/defichain-non-poolpair.strategy'; + +@Injectable() +export class DeFiChainStockStrategy extends DeFiChainNonPoolPairStrategy { + constructor( + readonly mailService: MailService, + readonly dexDeFiChainService: DexDeFiChainService, + readonly liquidityOrderRepo: LiquidityOrderRepository, + readonly liquidityOrderFactory: LiquidityOrderFactory, + ) { + super(mailService, dexDeFiChainService, liquidityOrderRepo, liquidityOrderFactory, ['DUSD', 'DFI']); + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-crypto.strategy.ts new file mode 100644 index 0000000000..47df137301 --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-crypto.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { MailService } from 'src/shared/services/mail.service'; +import { DexEthereumService } from '../../../services/dex-ethereum.service'; +import { EvmCryptoStrategy } from './base/evm-crypto.strategy'; + +@Injectable() +export class EthereumCryptoStrategy extends EvmCryptoStrategy { + constructor(mailService: MailService, dexEthereumService: DexEthereumService) { + super(mailService, dexEthereumService); + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-token.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-token.strategy.ts new file mode 100644 index 0000000000..99ff15ba34 --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-token.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { MailService } from 'src/shared/services/mail.service'; +import { DexEthereumService } from '../../../services/dex-ethereum.service'; +import { EvmTokenStrategy } from './base/evm-token.strategy'; + +@Injectable() +export class EthereumTokenStrategy extends EvmTokenStrategy { + constructor(mailService: MailService, dexEthereumService: DexEthereumService) { + super(mailService, dexEthereumService); + } +} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-crypto.strategy.ts deleted file mode 100644 index ee3eb041d8..0000000000 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-crypto.strategy.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { MailService } from 'src/shared/services/mail.service'; -import { DexBscService } from '../../services/dex-bsc.service'; -import { PurchaseLiquidityEvmCryptoStrategy } from './base/purchase-liquidity-evm-crypto.strategy'; - -@Injectable() -export class PurchaseLiquidityBscCryptoStrategy extends PurchaseLiquidityEvmCryptoStrategy { - constructor(mailService: MailService, dexBscService: DexBscService) { - super(mailService, dexBscService); - } -} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-token.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-token.strategy.ts deleted file mode 100644 index a067dc5f26..0000000000 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-bsc-token.strategy.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { MailService } from 'src/shared/services/mail.service'; -import { DexBscService } from '../../services/dex-bsc.service'; -import { PurchaseLiquidityEvmTokenStrategy } from './base/purchase-liquidity-evm-token.strategy'; - -@Injectable() -export class PurchaseLiquidityBscTokenStrategy extends PurchaseLiquidityEvmTokenStrategy { - constructor(mailService: MailService, dexBscService: DexBscService) { - super(mailService, dexBscService); - } -} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-crypto.strategy.ts deleted file mode 100644 index 252ae58d48..0000000000 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-crypto.strategy.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { LiquidityOrderRepository } from '../../repositories/liquidity-order.repository'; -import { DexDeFiChainService } from '../../services/dex-defichain.service'; -import { MailService } from 'src/shared/services/mail.service'; -import { LiquidityOrderFactory } from '../../factories/liquidity-order.factory'; -import { PurchaseLiquidityDeFiChainNonPoolPairStrategy } from './base/purchase-liquidity-defichain-non-poolpair.strategy'; - -@Injectable() -export class PurchaseLiquidityDeFiChainCryptoStrategy extends PurchaseLiquidityDeFiChainNonPoolPairStrategy { - constructor( - readonly mailService: MailService, - readonly dexDeFiChainService: DexDeFiChainService, - readonly liquidityOrderRepo: LiquidityOrderRepository, - readonly liquidityOrderFactory: LiquidityOrderFactory, - ) { - super(mailService, dexDeFiChainService, liquidityOrderRepo, liquidityOrderFactory, ['DFI']); - } -} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-stock.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-stock.strategy.ts deleted file mode 100644 index 3fa83d3d3f..0000000000 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-defichain-stock.strategy.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { LiquidityOrderRepository } from '../../repositories/liquidity-order.repository'; -import { DexDeFiChainService } from '../../services/dex-defichain.service'; -import { MailService } from 'src/shared/services/mail.service'; -import { LiquidityOrderFactory } from '../../factories/liquidity-order.factory'; -import { PurchaseLiquidityDeFiChainNonPoolPairStrategy } from './base/purchase-liquidity-defichain-non-poolpair.strategy'; - -@Injectable() -export class PurchaseLiquidityDeFiChainStockStrategy extends PurchaseLiquidityDeFiChainNonPoolPairStrategy { - constructor( - readonly mailService: MailService, - readonly dexDeFiChainService: DexDeFiChainService, - readonly liquidityOrderRepo: LiquidityOrderRepository, - readonly liquidityOrderFactory: LiquidityOrderFactory, - ) { - super(mailService, dexDeFiChainService, liquidityOrderRepo, liquidityOrderFactory, ['DUSD', 'DFI']); - } -} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy.ts deleted file mode 100644 index 13c8d4409a..0000000000 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { MailService } from 'src/shared/services/mail.service'; -import { DexEthereumService } from '../../services/dex-ethereum.service'; -import { PurchaseLiquidityEvmCryptoStrategy } from './base/purchase-liquidity-evm-crypto.strategy'; - -@Injectable() -export class PurchaseLiquidityEthereumCryptoStrategy extends PurchaseLiquidityEvmCryptoStrategy { - constructor(mailService: MailService, dexEthereumService: DexEthereumService) { - super(mailService, dexEthereumService); - } -} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-token.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-token.strategy.ts deleted file mode 100644 index 545bd92ffc..0000000000 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity-ethereum-token.strategy.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { MailService } from 'src/shared/services/mail.service'; -import { DexEthereumService } from '../../services/dex-ethereum.service'; -import { PurchaseLiquidityEvmTokenStrategy } from './base/purchase-liquidity-evm-token.strategy'; - -@Injectable() -export class PurchaseLiquidityEthereumTokenStrategy extends PurchaseLiquidityEvmTokenStrategy { - constructor(mailService: MailService, dexEthereumService: DexEthereumService) { - super(mailService, dexEthereumService); - } -} diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts new file mode 100644 index 0000000000..abd4aeeb2f --- /dev/null +++ b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts @@ -0,0 +1,74 @@ +import { forwardRef, Inject, Injectable } from '@nestjs/common'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { Asset, AssetCategory } from 'src/shared/models/asset/asset.entity'; +import { BscCryptoStrategy } from './impl/bsc-crypto.strategy'; +import { DeFiChainCryptoStrategy } from './impl/defichain-crypto.strategy'; +import { EthereumCryptoStrategy } from './impl/ethereum-crypto.strategy'; +import { PurchaseLiquidityStrategy } from './impl/base/purchase-liquidity.strategy'; +import { DeFiChainPoolPairStrategy } from './impl/defichain-poolpair.strategy'; +import { DeFiChainStockStrategy } from './impl/defichain-stock.strategy'; + +enum Alias { + DEFICHAIN_POOL_PAIR = 'DeFiChainPoolPair', + DEFICHAIN_STOCK = 'DeFiChainStock', + DEFICHAIN_CRYPTO = 'DeFiChainCrypto', + ETHEREUM_DEFAULT = 'EthereumDefault', + BSC_DEFAULT = 'BscDefault', +} + +export { Alias as PurchaseLiquidityStrategyAlias }; + +@Injectable() +export class PurchaseLiquidityStrategies { + protected readonly purchaseLiquidityStrategies = new Map(); + + constructor( + @Inject(forwardRef(() => DeFiChainPoolPairStrategy)) + deFiChainPoolPair: DeFiChainPoolPairStrategy, + deFiChainStock: DeFiChainStockStrategy, + deFiChainCrypto: DeFiChainCryptoStrategy, + ethereum: EthereumCryptoStrategy, + bsc: BscCryptoStrategy, + ) { + this.purchaseLiquidityStrategies.set(Alias.DEFICHAIN_POOL_PAIR, deFiChainPoolPair); + this.purchaseLiquidityStrategies.set(Alias.DEFICHAIN_STOCK, deFiChainStock); + this.purchaseLiquidityStrategies.set(Alias.DEFICHAIN_CRYPTO, deFiChainCrypto); + this.purchaseLiquidityStrategies.set(Alias.ETHEREUM_DEFAULT, ethereum); + this.purchaseLiquidityStrategies.set(Alias.BSC_DEFAULT, bsc); + } + + getPurchaseLiquidityStrategy(criteria: Asset | Alias): PurchaseLiquidityStrategy { + return criteria instanceof Asset + ? this.getPurchaseLiquidityStrategyByAsset(criteria) + : this.getPurchaseLiquidityStrategyByAlias(criteria); + } + + //*** HELPER METHODS ***// + + private getPurchaseLiquidityStrategyByAlias(alias: Alias): PurchaseLiquidityStrategy { + const strategy = this.purchaseLiquidityStrategies.get(alias); + + if (!strategy) throw new Error(`No PurchaseLiquidityStrategy found. Alias: ${alias}`); + + return strategy; + } + + private getPurchaseLiquidityStrategyByAsset(asset: Asset): PurchaseLiquidityStrategy { + const alias = this.getAlias(asset); + + return this.getPurchaseLiquidityStrategyByAlias(alias); + } + + private getAlias(asset: Asset): Alias { + const { blockchain, category: assetCategory } = asset; + + if (blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) { + if (assetCategory === AssetCategory.POOL_PAIR) return Alias.DEFICHAIN_POOL_PAIR; + if (assetCategory === AssetCategory.STOCK) return Alias.DEFICHAIN_STOCK; + if (assetCategory === AssetCategory.CRYPTO) return Alias.DEFICHAIN_CRYPTO; + } + + if (blockchain === Blockchain.ETHEREUM) return Alias.ETHEREUM_DEFAULT; + if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return Alias.BSC_DEFAULT; + } +} diff --git a/src/payment/models/dex/strategies/strategies.facade.ts b/src/payment/models/dex/strategies/strategies.facade.ts deleted file mode 100644 index 1b6b28b262..0000000000 --- a/src/payment/models/dex/strategies/strategies.facade.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { forwardRef, Inject, Injectable } from '@nestjs/common'; -import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { Asset, AssetCategory } from 'src/shared/models/asset/asset.entity'; -import { CheckLiquidityBscCryptoStrategy } from './check-liquidity/check-liquidity-bsc-crypto.strategy'; -import { CheckLiquidityDeFiChainDefaultStrategy } from './check-liquidity/check-liquidity-defichain-default.strategy'; -import { CheckLiquidityEthereumCryptoStrategy } from './check-liquidity/check-liquidity-ethereum-crypto.strategy'; -import { CheckLiquidityStrategy } from './check-liquidity/base/check-liquidity.strategy'; -import { CheckLiquidityDeFiChainPoolPairStrategy } from './check-liquidity/check-liquidity-defichain-poolpair.strategy'; -import { PurchaseLiquidityBscCryptoStrategy } from './purchase-liquidity/purchase-liquidity-bsc-crypto.strategy'; -import { PurchaseLiquidityDeFiChainCryptoStrategy } from './purchase-liquidity/purchase-liquidity-defichain-crypto.strategy'; -import { PurchaseLiquidityEthereumCryptoStrategy } from './purchase-liquidity/purchase-liquidity-ethereum-crypto.strategy'; -import { PurchaseLiquidityStrategy } from './purchase-liquidity/base/purchase-liquidity.strategy'; -import { PurchaseLiquidityDeFiChainPoolPairStrategy } from './purchase-liquidity/purchase-liquidity-defichain-poolpair.strategy'; -import { PurchaseLiquidityDeFiChainStockStrategy } from './purchase-liquidity/purchase-liquidity-defichain-stock.strategy'; - -export enum CheckLiquidityStrategyAlias { - DEFICHAIN_POOL_PAIR = 'DeFiChainPoolPair', - DEFICHAIN_DEFAULT = 'DeFiChainDefault', - ETHEREUM_DEFAULT = 'EthereumDefault', - BSC_DEFAULT = 'BscDefault', -} - -export enum PurchaseLiquidityStrategyAlias { - DEFICHAIN_POOL_PAIR = 'DeFiChainPoolPair', - DEFICHAIN_STOCK = 'DeFiChainStock', - DEFICHAIN_CRYPTO = 'DeFiChainCrypto', - ETHEREUM_DEFAULT = 'EthereumDefault', - BSC_DEFAULT = 'BscDefault', -} - -@Injectable() -export class DexStrategiesFacade { - protected readonly checkLiquidityStrategies = new Map(); - protected readonly purchaseLiquidityStrategies = new Map(); - - constructor( - checkLiquidityDeFiChainPoolPairStrategy: CheckLiquidityDeFiChainPoolPairStrategy, - checkLiquidityDeFiChainDefaultStrategy: CheckLiquidityDeFiChainDefaultStrategy, - checkLiquidityEthereumStrategy: CheckLiquidityEthereumCryptoStrategy, - checkLiquidityBscStrategy: CheckLiquidityBscCryptoStrategy, - @Inject(forwardRef(() => PurchaseLiquidityDeFiChainPoolPairStrategy)) - purchaseLiquidityDeFiChainPoolPairStrategy: PurchaseLiquidityDeFiChainPoolPairStrategy, - purchaseLiquidityDeFiChainStockStrategy: PurchaseLiquidityDeFiChainStockStrategy, - purchaseLiquidityDeFiChainCryptoStrategy: PurchaseLiquidityDeFiChainCryptoStrategy, - purchaseLiquidityEthereumStrategy: PurchaseLiquidityEthereumCryptoStrategy, - purchaseLiquidityBscStrategy: PurchaseLiquidityBscCryptoStrategy, - ) { - this.checkLiquidityStrategies.set( - CheckLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR, - checkLiquidityDeFiChainPoolPairStrategy, - ); - - this.checkLiquidityStrategies.set( - CheckLiquidityStrategyAlias.DEFICHAIN_DEFAULT, - checkLiquidityDeFiChainDefaultStrategy, - ); - - this.checkLiquidityStrategies.set(CheckLiquidityStrategyAlias.ETHEREUM_DEFAULT, checkLiquidityEthereumStrategy); - - this.checkLiquidityStrategies.set(CheckLiquidityStrategyAlias.BSC_DEFAULT, checkLiquidityBscStrategy); - - this.purchaseLiquidityStrategies.set( - PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR, - purchaseLiquidityDeFiChainPoolPairStrategy, - ); - - this.purchaseLiquidityStrategies.set( - PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK, - purchaseLiquidityDeFiChainStockStrategy, - ); - - this.purchaseLiquidityStrategies.set( - PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO, - purchaseLiquidityDeFiChainCryptoStrategy, - ); - - this.purchaseLiquidityStrategies.set( - PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT, - purchaseLiquidityEthereumStrategy, - ); - - this.purchaseLiquidityStrategies.set(PurchaseLiquidityStrategyAlias.BSC_DEFAULT, purchaseLiquidityBscStrategy); - } - - getCheckLiquidityStrategy(criteria: Asset | CheckLiquidityStrategyAlias): CheckLiquidityStrategy { - return criteria instanceof Asset - ? this.getCheckLiquidityStrategyByAsset(criteria) - : this.getCheckLiquidityStrategyByAlias(criteria); - } - - getPurchaseLiquidityStrategy(criteria: Asset | PurchaseLiquidityStrategyAlias): PurchaseLiquidityStrategy { - return criteria instanceof Asset - ? this.getPurchaseLiquidityStrategyByAsset(criteria) - : this.getPurchaseLiquidityStrategyByAlias(criteria); - } - - //*** HELPER METHODS ***// - - private getCheckLiquidityStrategyByAlias(alias: CheckLiquidityStrategyAlias): CheckLiquidityStrategy { - const strategy = this.checkLiquidityStrategies.get(alias); - - if (!strategy) throw new Error(`No CheckLiquidityStrategy found. Alias: ${alias}`); - - return strategy; - } - - private getCheckLiquidityStrategyByAsset(asset: Asset): CheckLiquidityStrategy { - const alias = this.getCheckLiquidityStrategyAlias(asset); - - return this.getCheckLiquidityStrategyByAlias(alias); - } - - private getPurchaseLiquidityStrategyByAlias(alias: PurchaseLiquidityStrategyAlias): PurchaseLiquidityStrategy { - const strategy = this.purchaseLiquidityStrategies.get(alias); - - if (!strategy) throw new Error(`No PurchaseLiquidityStrategy found. Alias: ${alias}`); - - return strategy; - } - - private getPurchaseLiquidityStrategyByAsset(asset: Asset): PurchaseLiquidityStrategy { - const alias = this.getPurchaseLiquidityStrategyAlias(asset); - - return this.getPurchaseLiquidityStrategyByAlias(alias); - } - - private getCheckLiquidityStrategyAlias(asset: Asset): CheckLiquidityStrategyAlias { - const { blockchain, category: assetCategory } = asset; - - if (blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) { - if (assetCategory === AssetCategory.POOL_PAIR) return CheckLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR; - return CheckLiquidityStrategyAlias.DEFICHAIN_DEFAULT; - } - - if (blockchain === Blockchain.ETHEREUM) return CheckLiquidityStrategyAlias.ETHEREUM_DEFAULT; - if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return CheckLiquidityStrategyAlias.BSC_DEFAULT; - } - - private getPurchaseLiquidityStrategyAlias(asset: Asset): PurchaseLiquidityStrategyAlias { - const { blockchain, category: assetCategory } = asset; - - if (blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) { - if (assetCategory === AssetCategory.POOL_PAIR) return PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR; - if (assetCategory === AssetCategory.STOCK) return PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK; - if (assetCategory === AssetCategory.CRYPTO) return PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO; - } - - if (blockchain === Blockchain.ETHEREUM) return PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT; - if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return PurchaseLiquidityStrategyAlias.BSC_DEFAULT; - } -} From 6f7f43334901c3b9ddc337e5e0d59b18ed534593 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Thu, 29 Sep 2022 12:13:26 +0200 Subject: [PATCH 03/30] [DEV-622] added new strategies to facades --- .../__tests__/check-liquidity.facade.spec.ts | 157 +++++++++----- .../check-liquidity/check-liquidity.facade.ts | 41 +++- .../purchase-liquidity.facade.spec.ts | 195 ++++++++++++------ .../purchase-liquidity.facade.ts | 51 +++-- 4 files changed, 299 insertions(+), 145 deletions(-) diff --git a/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts b/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts index d893f1995c..a64d639906 100644 --- a/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts +++ b/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts @@ -13,14 +13,21 @@ import { DeFiChainDefaultStrategy } from '../impl/defichain-default.strategy'; import { DeFiChainPoolPairStrategy } from '../impl/defichain-poolpair.strategy'; import { EthereumCryptoStrategy } from '../impl/ethereum-crypto.strategy'; import { CheckLiquidityAlias } from '../check-liquidity.facade'; +import { BitcoinStrategy } from '../impl/bitcoin.strategy'; +import { BscTokenStrategy } from '../impl/bsc-token.strategy'; +import { EthereumTokenStrategy } from '../impl/ethereum-token.strategy'; +import { DexBitcoinService } from '../../../services/dex-bitcoin.service'; describe('CheckLiquidityStrategies', () => { let nodeService: NodeService; + let bitcoin: BitcoinStrategy; + let bscCrypto: BscCryptoStrategy; + let bscToken: BscTokenStrategy; let deFiChainPoolPair: DeFiChainPoolPairStrategy; let deFiChainDefault: DeFiChainDefaultStrategy; - let ethereum: EthereumCryptoStrategy; - let bsc: BscCryptoStrategy; + let ethereumCrypto: EthereumCryptoStrategy; + let ethereumToken: EthereumTokenStrategy; let facade: CheckLiquidityStrategiesWrapper; @@ -28,97 +35,121 @@ describe('CheckLiquidityStrategies', () => { nodeService = mock(); jest.spyOn(nodeService, 'getConnectedNode').mockImplementation(() => new BehaviorSubject(null)); + bitcoin = new BitcoinStrategy(mock()); + bscCrypto = new BscCryptoStrategy(mock()); + bscToken = new BscTokenStrategy(mock()); deFiChainPoolPair = new DeFiChainPoolPairStrategy(); deFiChainDefault = new DeFiChainDefaultStrategy(mock()); - ethereum = new EthereumCryptoStrategy(mock()); - bsc = new BscCryptoStrategy(mock()); - - facade = new CheckLiquidityStrategiesWrapper(deFiChainPoolPair, deFiChainDefault, ethereum, bsc); + ethereumCrypto = new EthereumCryptoStrategy(mock()); + ethereumToken = new EthereumTokenStrategy(mock()); + + facade = new CheckLiquidityStrategiesWrapper( + bitcoin, + bscCrypto, + bscToken, + deFiChainDefault, + deFiChainPoolPair, + ethereumCrypto, + ethereumToken, + ); }); describe('#constructor(...)', () => { it('adds all checkLiquidityStrategies to a map', () => { - expect([...facade.getCheckLiquidityStrategies().entries()].length).toBe(4); + expect([...facade.getStrategies().entries()].length).toBe(7); + }); + + it('assigns strategies to all aliases', () => { + expect([...facade.getStrategies().entries()].length).toBe(Object.values(CheckLiquidityAlias).length); }); it('sets all required checkLiquidityStrategies aliases', () => { - const aliases = [...facade.getCheckLiquidityStrategies().keys()]; + const aliases = [...facade.getStrategies().keys()]; + expect(aliases.includes(CheckLiquidityAlias.BITCOIN)).toBe(true); + expect(aliases.includes(CheckLiquidityAlias.BSC_CRYPTO)).toBe(true); + expect(aliases.includes(CheckLiquidityAlias.BSC_TOKEN)).toBe(true); expect(aliases.includes(CheckLiquidityAlias.DEFICHAIN_POOL_PAIR)).toBe(true); expect(aliases.includes(CheckLiquidityAlias.DEFICHAIN_DEFAULT)).toBe(true); - expect(aliases.includes(CheckLiquidityAlias.ETHEREUM_DEFAULT)).toBe(true); - expect(aliases.includes(CheckLiquidityAlias.BSC_DEFAULT)).toBe(true); + expect(aliases.includes(CheckLiquidityAlias.ETHEREUM_CRYPTO)).toBe(true); + expect(aliases.includes(CheckLiquidityAlias.ETHEREUM_TOKEN)).toBe(true); }); it('assigns proper checkLiquidityStrategies to aliases', () => { - expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityAlias.DEFICHAIN_POOL_PAIR)).toBeInstanceOf( + expect(facade.getStrategies().get(CheckLiquidityAlias.BITCOIN)).toBeInstanceOf(BitcoinStrategy); + expect(facade.getStrategies().get(CheckLiquidityAlias.BSC_CRYPTO)).toBeInstanceOf(BscCryptoStrategy); + expect(facade.getStrategies().get(CheckLiquidityAlias.BSC_TOKEN)).toBeInstanceOf(BscTokenStrategy); + expect(facade.getStrategies().get(CheckLiquidityAlias.DEFICHAIN_POOL_PAIR)).toBeInstanceOf( DeFiChainPoolPairStrategy, ); - - expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityAlias.DEFICHAIN_DEFAULT)).toBeInstanceOf( + expect(facade.getStrategies().get(CheckLiquidityAlias.DEFICHAIN_DEFAULT)).toBeInstanceOf( DeFiChainDefaultStrategy, ); - - expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityAlias.ETHEREUM_DEFAULT)).toBeInstanceOf( - EthereumCryptoStrategy, - ); - - expect(facade.getCheckLiquidityStrategies().get(CheckLiquidityAlias.BSC_DEFAULT)).toBeInstanceOf( - BscCryptoStrategy, - ); + expect(facade.getStrategies().get(CheckLiquidityAlias.ETHEREUM_CRYPTO)).toBeInstanceOf(EthereumCryptoStrategy); + expect(facade.getStrategies().get(CheckLiquidityAlias.ETHEREUM_TOKEN)).toBeInstanceOf(EthereumTokenStrategy); }); }); describe('#getCheckLiquidityStrategy(...)', () => { describe('getting strategy by Asset', () => { - it('gets DEFICHAIN_POOL_PAIR strategy for DEFICHAIN', () => { + it('gets BITCOIN strategy for BITCOIN', () => { + const strategy = facade.getCheckLiquidityStrategy(createCustomAsset({ blockchain: Blockchain.BITCOIN })); + + expect(strategy).toBeInstanceOf(BitcoinStrategy); + }); + + it('gets BSC_CRYPTO strategy', () => { const strategy = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.POOL_PAIR }), + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.CRYPTO }), ); - expect(strategy).toBeInstanceOf(DeFiChainPoolPairStrategy); + expect(strategy).toBeInstanceOf(BscCryptoStrategy); }); - it('gets DEFICHAIN_DEFAULT strategy for DEFICHAIN', () => { - const strategyCrypto = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.CRYPTO }), + it('gets BSC_TOKEN strategy', () => { + const strategy = facade.getCheckLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.STOCK }), ); - expect(strategyCrypto).toBeInstanceOf(DeFiChainDefaultStrategy); + expect(strategy).toBeInstanceOf(BscTokenStrategy); + }); - const strategyStock = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.STOCK }), + it('gets DEFICHAIN_POOL_PAIR strategy for DEFICHAIN', () => { + const strategy = facade.getCheckLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.POOL_PAIR }), ); - expect(strategyStock).toBeInstanceOf(DeFiChainDefaultStrategy); + expect(strategy).toBeInstanceOf(DeFiChainPoolPairStrategy); }); - it('gets DEFICHAIN_DEFAULT strategy for BITCOIN', () => { + it('gets DEFICHAIN_DEFAULT strategy for DEFICHAIN', () => { const strategyCrypto = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BITCOIN, category: AssetCategory.CRYPTO }), + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.CRYPTO }), ); expect(strategyCrypto).toBeInstanceOf(DeFiChainDefaultStrategy); const strategyStock = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BITCOIN, category: AssetCategory.STOCK }), + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.STOCK }), ); expect(strategyStock).toBeInstanceOf(DeFiChainDefaultStrategy); }); - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getCheckLiquidityStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); + it('gets ETHEREUM_CRYPTO strategy', () => { + const strategy = facade.getCheckLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.CRYPTO }), + ); expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); }); - it('gets BSC_DEFAULT strategy', () => { + it('gets ETHEREUM_TOKEN strategy', () => { const strategy = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN }), + createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.STOCK }), ); - expect(strategy).toBeInstanceOf(BscCryptoStrategy); + expect(strategy).toBeInstanceOf(EthereumTokenStrategy); }); it('fails to get strategy for non-supported Blockchain', () => { @@ -131,6 +162,24 @@ describe('CheckLiquidityStrategies', () => { }); describe('getting strategy by CheckLiquidityAlias', () => { + it('gets BITCOIN strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.BITCOIN); + + expect(strategy).toBeInstanceOf(BitcoinStrategy); + }); + + it('gets BSC_CRYPTO strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.BSC_CRYPTO); + + expect(strategy).toBeInstanceOf(BscCryptoStrategy); + }); + + it('gets BSC_TOKEN strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.BSC_TOKEN); + + expect(strategy).toBeInstanceOf(BscTokenStrategy); + }); + it('gets DEFICHAIN_POOL_PAIR strategy', () => { const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.DEFICHAIN_POOL_PAIR); @@ -143,16 +192,16 @@ describe('CheckLiquidityStrategies', () => { expect(strategyCrypto).toBeInstanceOf(DeFiChainDefaultStrategy); }); - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.ETHEREUM_DEFAULT); + it('gets ETHEREUM_CRYPTO strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.ETHEREUM_CRYPTO); expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); }); - it('gets BSC_DEFAULT strategy', () => { - const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.BSC_DEFAULT); + it('gets ETHEREUM_TOKEN strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.ETHEREUM_TOKEN); - expect(strategy).toBeInstanceOf(BscCryptoStrategy); + expect(strategy).toBeInstanceOf(EthereumTokenStrategy); }); it('fails to get strategy for non-supported CheckLiquidityAlias', () => { @@ -168,20 +217,18 @@ describe('CheckLiquidityStrategies', () => { class CheckLiquidityStrategiesWrapper extends CheckLiquidityStrategies { constructor( - checkLiquidityDeFiChainPoolPairStrategy: DeFiChainPoolPairStrategy, - checkLiquidityDeFiChainDefaultStrategy: DeFiChainDefaultStrategy, - checkLiquidityEthereumStrategy: EthereumCryptoStrategy, - checkLiquidityBSCStrategy: BscCryptoStrategy, + bitcoin: BitcoinStrategy, + bscCrypto: BscCryptoStrategy, + bscToken: BscTokenStrategy, + deFiChainDefault: DeFiChainDefaultStrategy, + deFiChainPoolPair: DeFiChainPoolPairStrategy, + ethereumCrypto: EthereumCryptoStrategy, + ethereumToken: EthereumTokenStrategy, ) { - super( - checkLiquidityDeFiChainPoolPairStrategy, - checkLiquidityDeFiChainDefaultStrategy, - checkLiquidityEthereumStrategy, - checkLiquidityBSCStrategy, - ); + super(bitcoin, bscCrypto, bscToken, deFiChainDefault, deFiChainPoolPair, ethereumCrypto, ethereumToken); } - getCheckLiquidityStrategies() { + getStrategies() { return this.strategies; } } diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts index f618ec7f76..179c92e894 100644 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts +++ b/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts @@ -2,16 +2,22 @@ import { Injectable } from '@nestjs/common'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; import { Asset, AssetCategory } from 'src/shared/models/asset/asset.entity'; import { CheckLiquidityStrategy } from './impl/base/check-liquidity.strategy'; +import { BitcoinStrategy } from './impl/bitcoin.strategy'; import { BscCryptoStrategy } from './impl/bsc-crypto.strategy'; +import { BscTokenStrategy } from './impl/bsc-token.strategy'; import { DeFiChainDefaultStrategy } from './impl/defichain-default.strategy'; import { DeFiChainPoolPairStrategy } from './impl/defichain-poolpair.strategy'; import { EthereumCryptoStrategy } from './impl/ethereum-crypto.strategy'; +import { EthereumTokenStrategy } from './impl/ethereum-token.strategy'; enum Alias { + BITCOIN = 'Bitcoin', + BSC_CRYPTO = 'BscCrypto', + BSC_TOKEN = 'BscToken', DEFICHAIN_POOL_PAIR = 'DeFiChainPoolPair', DEFICHAIN_DEFAULT = 'DeFiChainDefault', - ETHEREUM_DEFAULT = 'EthereumDefault', - BSC_DEFAULT = 'BscDefault', + ETHEREUM_CRYPTO = 'EthereumCrypto', + ETHEREUM_TOKEN = 'EthereumToken', } export { Alias as CheckLiquidityAlias }; @@ -21,15 +27,21 @@ export class CheckLiquidityStrategies { protected readonly strategies = new Map(); constructor( - deFiChainPoolPair: DeFiChainPoolPairStrategy, + bitcoin: BitcoinStrategy, + bscCrypto: BscCryptoStrategy, + bscToken: BscTokenStrategy, deFiChainDefault: DeFiChainDefaultStrategy, - ethereum: EthereumCryptoStrategy, - bsc: BscCryptoStrategy, + deFiChainPoolPair: DeFiChainPoolPairStrategy, + ethereumCrypto: EthereumCryptoStrategy, + ethereumToken: EthereumTokenStrategy, ) { + this.strategies.set(Alias.BITCOIN, bitcoin); + this.strategies.set(Alias.BSC_CRYPTO, bscCrypto); + this.strategies.set(Alias.BSC_TOKEN, bscToken); this.strategies.set(Alias.DEFICHAIN_POOL_PAIR, deFiChainPoolPair); this.strategies.set(Alias.DEFICHAIN_DEFAULT, deFiChainDefault); - this.strategies.set(Alias.ETHEREUM_DEFAULT, ethereum); - this.strategies.set(Alias.BSC_DEFAULT, bsc); + this.strategies.set(Alias.ETHEREUM_CRYPTO, ethereumCrypto); + this.strategies.set(Alias.ETHEREUM_TOKEN, ethereumToken); } getCheckLiquidityStrategy(criteria: Asset | Alias): CheckLiquidityStrategy { @@ -57,12 +69,21 @@ export class CheckLiquidityStrategies { private getAlias(asset: Asset): Alias { const { blockchain, category: assetCategory } = asset; - if (blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) { + if (blockchain === Blockchain.BITCOIN) return Alias.BITCOIN; + + if (blockchain === Blockchain.BINANCE_SMART_CHAIN) { + if (assetCategory === AssetCategory.CRYPTO) return Alias.BSC_CRYPTO; + if (assetCategory === AssetCategory.STOCK) return Alias.BSC_TOKEN; + } + + if (blockchain === Blockchain.DEFICHAIN) { if (assetCategory === AssetCategory.POOL_PAIR) return Alias.DEFICHAIN_POOL_PAIR; return Alias.DEFICHAIN_DEFAULT; } - if (blockchain === Blockchain.ETHEREUM) return Alias.ETHEREUM_DEFAULT; - if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return Alias.BSC_DEFAULT; + if (blockchain === Blockchain.ETHEREUM) { + if (assetCategory === AssetCategory.CRYPTO) return Alias.ETHEREUM_CRYPTO; + if (assetCategory === AssetCategory.STOCK) return Alias.ETHEREUM_TOKEN; + } } } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts b/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts index 79d943c765..7cb2afc9ad 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts @@ -12,21 +12,27 @@ import { LiquidityOrderRepository } from '../../../repositories/liquidity-order. import { DexBscService } from '../../../services/dex-bsc.service'; import { DexDeFiChainService } from '../../../services/dex-defichain.service'; import { DexService } from '../../../services/dex.service'; +import { BitcoinStrategy } from '../impl/bitcoin.strategy'; import { BscCryptoStrategy } from '../impl/bsc-crypto.strategy'; +import { BscTokenStrategy } from '../impl/bsc-token.strategy'; import { DeFiChainCryptoStrategy } from '../impl/defichain-crypto.strategy'; import { DeFiChainPoolPairStrategy } from '../impl/defichain-poolpair.strategy'; import { DeFiChainStockStrategy } from '../impl/defichain-stock.strategy'; import { EthereumCryptoStrategy } from '../impl/ethereum-crypto.strategy'; +import { EthereumTokenStrategy } from '../impl/ethereum-token.strategy'; import { PurchaseLiquidityStrategyAlias, PurchaseLiquidityStrategies } from '../purchase-liquidity.facade'; describe('PurchaseLiquidityStrategies', () => { let nodeService: NodeService; + let bitcoin: BitcoinStrategy; + let bscCrypto: BscCryptoStrategy; + let bscToken: BscTokenStrategy; let deFiChainPoolPair: DeFiChainPoolPairStrategy; let deFiChainStock: DeFiChainStockStrategy; let deFiChainCrypto: DeFiChainCryptoStrategy; - let ethereum: EthereumCryptoStrategy; - let bsc: BscCryptoStrategy; + let ethereumCrypto: EthereumCryptoStrategy; + let ethereumToken: EthereumTokenStrategy; let facade: PurchaseLiquidityStrategiesWrapper; @@ -34,6 +40,10 @@ describe('PurchaseLiquidityStrategies', () => { nodeService = mock(); jest.spyOn(nodeService, 'getConnectedNode').mockImplementation(() => new BehaviorSubject(null)); + bitcoin = new BitcoinStrategy(mock()); + bscCrypto = new BscCryptoStrategy(mock(), mock()); + bscToken = new BscTokenStrategy(mock(), mock()); + deFiChainPoolPair = new DeFiChainPoolPairStrategy( nodeService, mock(), @@ -55,66 +65,87 @@ describe('PurchaseLiquidityStrategies', () => { mock(), mock(), ); - ethereum = new EthereumCryptoStrategy(mock(), mock()); - bsc = new BscCryptoStrategy(mock(), mock()); - - facade = new PurchaseLiquidityStrategiesWrapper(deFiChainPoolPair, deFiChainStock, deFiChainCrypto, ethereum, bsc); + ethereumCrypto = new EthereumCryptoStrategy(mock(), mock()); + ethereumToken = new EthereumTokenStrategy(mock(), mock()); + + facade = new PurchaseLiquidityStrategiesWrapper( + bitcoin, + bscCrypto, + bscToken, + deFiChainCrypto, + deFiChainPoolPair, + deFiChainStock, + ethereumCrypto, + ethereumToken, + ); }); describe('#constructor(...)', () => { it('adds all purchaseLiquidityStrategies to a map', () => { - expect([...facade.getPurchaseLiquidityStrategies().entries()].length).toBe(5); + expect([...facade.getStrategies().entries()].length).toBe(8); + }); + + it('assigns strategies to all aliases', () => { + expect([...facade.getStrategies().entries()].length).toBe(Object.values(PurchaseLiquidityStrategyAlias).length); }); it('sets all required purchaseLiquidityStrategies aliases', () => { - const aliases = [...facade.getPurchaseLiquidityStrategies().keys()]; + const aliases = [...facade.getStrategies().keys()]; + expect(aliases.includes(PurchaseLiquidityStrategyAlias.BITCOIN)).toBe(true); + expect(aliases.includes(PurchaseLiquidityStrategyAlias.BSC_CRYPTO)).toBe(true); + expect(aliases.includes(PurchaseLiquidityStrategyAlias.BSC_TOKEN)).toBe(true); expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR)).toBe(true); expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK)).toBe(true); expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO)).toBe(true); - expect(aliases.includes(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT)).toBe(true); - expect(aliases.includes(PurchaseLiquidityStrategyAlias.BSC_DEFAULT)).toBe(true); + expect(aliases.includes(PurchaseLiquidityStrategyAlias.ETHEREUM_CRYPTO)).toBe(true); + expect(aliases.includes(PurchaseLiquidityStrategyAlias.ETHEREUM_TOKEN)).toBe(true); }); it('assigns proper purchaseLiquidityStrategies to aliases', () => { - expect( - facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR), - ).toBeInstanceOf(DeFiChainPoolPairStrategy); - - expect( - facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK), - ).toBeInstanceOf(DeFiChainStockStrategy); - - expect( - facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO), - ).toBeInstanceOf(DeFiChainCryptoStrategy); - - expect( - facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT), - ).toBeInstanceOf(EthereumCryptoStrategy); - - expect(facade.getPurchaseLiquidityStrategies().get(PurchaseLiquidityStrategyAlias.BSC_DEFAULT)).toBeInstanceOf( - BscCryptoStrategy, + expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.BITCOIN)).toBeInstanceOf(BitcoinStrategy); + expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.BSC_CRYPTO)).toBeInstanceOf(BscCryptoStrategy); + expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.BSC_TOKEN)).toBeInstanceOf(BscTokenStrategy); + expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO)).toBeInstanceOf( + DeFiChainCryptoStrategy, + ); + expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR)).toBeInstanceOf( + DeFiChainPoolPairStrategy, + ); + expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK)).toBeInstanceOf( + DeFiChainStockStrategy, + ); + expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.ETHEREUM_CRYPTO)).toBeInstanceOf( + EthereumCryptoStrategy, + ); + expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.ETHEREUM_TOKEN)).toBeInstanceOf( + EthereumTokenStrategy, ); }); }); describe('#getPurchaseLiquidityStrategy(...)', () => { describe('getting strategy by Asset', () => { - it('gets DEFICHAIN_POOL_PAIR strategy for DEFICHAIN Pool Pair', () => { + it('gets BITCOIN strategy for BITCOIN Crypto', () => { + const strategy = facade.getPurchaseLiquidityStrategy(createCustomAsset({ blockchain: Blockchain.BITCOIN })); + + expect(strategy).toBeInstanceOf(BitcoinStrategy); + }); + + it('gets BSC_CRYPTO strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.POOL_PAIR }), + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.CRYPTO }), ); - expect(strategy).toBeInstanceOf(DeFiChainPoolPairStrategy); + expect(strategy).toBeInstanceOf(BscCryptoStrategy); }); - it('gets DEFICHAIN_STOCK strategy for DEFICHAIN Stock', () => { + it('gets BSC_TOKEN strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.STOCK }), + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.STOCK }), ); - expect(strategy).toBeInstanceOf(DeFiChainStockStrategy); + expect(strategy).toBeInstanceOf(BscTokenStrategy); }); it('gets DEFICHAIN_CRYPTO strategy for DEFICHAIN Crypto', () => { @@ -125,26 +156,36 @@ describe('PurchaseLiquidityStrategies', () => { expect(strategy).toBeInstanceOf(DeFiChainCryptoStrategy); }); - it('gets DEFICHAIN_CRYPTO strategy for BITCOIN Crypto', () => { + it('gets DEFICHAIN_POOL_PAIR strategy for DEFICHAIN Pool Pair', () => { const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BITCOIN, category: AssetCategory.CRYPTO }), + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.POOL_PAIR }), ); - expect(strategy).toBeInstanceOf(DeFiChainCryptoStrategy); + expect(strategy).toBeInstanceOf(DeFiChainPoolPairStrategy); }); - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); + it('gets DEFICHAIN_STOCK strategy for DEFICHAIN Stock', () => { + const strategy = facade.getPurchaseLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, category: AssetCategory.STOCK }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainStockStrategy); + }); + + it('gets ETHEREUM_CRYPTO strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy( + createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.CRYPTO }), + ); expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); }); - it('gets BSC_DEFAULT strategy', () => { + it('gets ETHEREUM_TOKEN strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN }), + createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.STOCK }), ); - expect(strategy).toBeInstanceOf(BscCryptoStrategy); + expect(strategy).toBeInstanceOf(EthereumTokenStrategy); }); it('fails to get strategy for non-supported Blockchain', () => { @@ -167,16 +208,22 @@ describe('PurchaseLiquidityStrategies', () => { }); describe('getting strategy by Alias', () => { - it('gets DEFICHAIN_POOL_PAIR strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR); + it('gets BSC_CRYPTO strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.BITCOIN); - expect(strategy).toBeInstanceOf(DeFiChainPoolPairStrategy); + expect(strategy).toBeInstanceOf(BitcoinStrategy); }); - it('gets DEFICHAIN_STOCK strategy', () => { - const strategyCrypto = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK); + it('gets BSC_CRYPTO strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.BSC_CRYPTO); - expect(strategyCrypto).toBeInstanceOf(DeFiChainStockStrategy); + expect(strategy).toBeInstanceOf(BscCryptoStrategy); + }); + + it('gets BSC_TOKEN strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.BSC_TOKEN); + + expect(strategy).toBeInstanceOf(BscTokenStrategy); }); it('gets DEFICHAIN_CRYPTO strategy', () => { @@ -185,16 +232,28 @@ describe('PurchaseLiquidityStrategies', () => { expect(strategyCrypto).toBeInstanceOf(DeFiChainCryptoStrategy); }); - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.ETHEREUM_DEFAULT); + it('gets DEFICHAIN_POOL_PAIR strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR); + + expect(strategy).toBeInstanceOf(DeFiChainPoolPairStrategy); + }); + + it('gets DEFICHAIN_STOCK strategy', () => { + const strategyCrypto = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK); + + expect(strategyCrypto).toBeInstanceOf(DeFiChainStockStrategy); + }); + + it('gets ETHEREUM_CRYPTO strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.ETHEREUM_CRYPTO); expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); }); - it('gets BSC_DEFAULT strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.BSC_DEFAULT); + it('gets ETHEREUM_TOKEN strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.ETHEREUM_TOKEN); - expect(strategy).toBeInstanceOf(BscCryptoStrategy); + expect(strategy).toBeInstanceOf(EthereumTokenStrategy); }); it('fails to get strategy for non-supported Alias', () => { @@ -210,22 +269,28 @@ describe('PurchaseLiquidityStrategies', () => { class PurchaseLiquidityStrategiesWrapper extends PurchaseLiquidityStrategies { constructor( - purchaseLiquidityDeFiChainPoolPairStrategy: DeFiChainPoolPairStrategy, - purchaseLiquidityDeFiChainStockStrategy: DeFiChainStockStrategy, - purchaseLiquidityDeFiChainCryptoStrategy: DeFiChainCryptoStrategy, - purchaseLiquidityEthereumStrategy: EthereumCryptoStrategy, - purchaseLiquidityBSCStrategy: BscCryptoStrategy, + bitcoin: BitcoinStrategy, + bscCrypto: BscCryptoStrategy, + bscToken: BscTokenStrategy, + deFiChainCrypto: DeFiChainCryptoStrategy, + deFiChainPoolPair: DeFiChainPoolPairStrategy, + deFiChainStock: DeFiChainStockStrategy, + ethereumCrypto: EthereumCryptoStrategy, + ethereumToken: EthereumTokenStrategy, ) { super( - purchaseLiquidityDeFiChainPoolPairStrategy, - purchaseLiquidityDeFiChainStockStrategy, - purchaseLiquidityDeFiChainCryptoStrategy, - purchaseLiquidityEthereumStrategy, - purchaseLiquidityBSCStrategy, + bitcoin, + bscCrypto, + bscToken, + deFiChainCrypto, + deFiChainPoolPair, + deFiChainStock, + ethereumCrypto, + ethereumToken, ); } - getPurchaseLiquidityStrategies() { - return this.purchaseLiquidityStrategies; + getStrategies() { + return this.strategies; } } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts index abd4aeeb2f..48eddc7dd0 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts @@ -7,34 +7,46 @@ import { EthereumCryptoStrategy } from './impl/ethereum-crypto.strategy'; import { PurchaseLiquidityStrategy } from './impl/base/purchase-liquidity.strategy'; import { DeFiChainPoolPairStrategy } from './impl/defichain-poolpair.strategy'; import { DeFiChainStockStrategy } from './impl/defichain-stock.strategy'; +import { BscTokenStrategy } from './impl/bsc-token.strategy'; +import { BitcoinStrategy } from './impl/bitcoin.strategy'; +import { EthereumTokenStrategy } from './impl/ethereum-token.strategy'; enum Alias { + BITCOIN = 'Bitcoin', + BSC_CRYPTO = 'BscCrypto', + BSC_TOKEN = 'BscToken', DEFICHAIN_POOL_PAIR = 'DeFiChainPoolPair', DEFICHAIN_STOCK = 'DeFiChainStock', DEFICHAIN_CRYPTO = 'DeFiChainCrypto', - ETHEREUM_DEFAULT = 'EthereumDefault', - BSC_DEFAULT = 'BscDefault', + ETHEREUM_CRYPTO = 'EthereumCrypto', + ETHEREUM_TOKEN = 'EthereumToken', } export { Alias as PurchaseLiquidityStrategyAlias }; @Injectable() export class PurchaseLiquidityStrategies { - protected readonly purchaseLiquidityStrategies = new Map(); + protected readonly strategies = new Map(); constructor( + bitcoin: BitcoinStrategy, + bscCrypto: BscCryptoStrategy, + bscToken: BscTokenStrategy, + deFiChainCrypto: DeFiChainCryptoStrategy, @Inject(forwardRef(() => DeFiChainPoolPairStrategy)) deFiChainPoolPair: DeFiChainPoolPairStrategy, deFiChainStock: DeFiChainStockStrategy, - deFiChainCrypto: DeFiChainCryptoStrategy, - ethereum: EthereumCryptoStrategy, - bsc: BscCryptoStrategy, + ethereumCrypto: EthereumCryptoStrategy, + ethereumToken: EthereumTokenStrategy, ) { - this.purchaseLiquidityStrategies.set(Alias.DEFICHAIN_POOL_PAIR, deFiChainPoolPair); - this.purchaseLiquidityStrategies.set(Alias.DEFICHAIN_STOCK, deFiChainStock); - this.purchaseLiquidityStrategies.set(Alias.DEFICHAIN_CRYPTO, deFiChainCrypto); - this.purchaseLiquidityStrategies.set(Alias.ETHEREUM_DEFAULT, ethereum); - this.purchaseLiquidityStrategies.set(Alias.BSC_DEFAULT, bsc); + this.strategies.set(Alias.BITCOIN, bitcoin); + this.strategies.set(Alias.BSC_CRYPTO, bscCrypto); + this.strategies.set(Alias.BSC_TOKEN, bscToken); + this.strategies.set(Alias.DEFICHAIN_POOL_PAIR, deFiChainPoolPair); + this.strategies.set(Alias.DEFICHAIN_STOCK, deFiChainStock); + this.strategies.set(Alias.DEFICHAIN_CRYPTO, deFiChainCrypto); + this.strategies.set(Alias.ETHEREUM_CRYPTO, ethereumCrypto); + this.strategies.set(Alias.ETHEREUM_TOKEN, ethereumToken); } getPurchaseLiquidityStrategy(criteria: Asset | Alias): PurchaseLiquidityStrategy { @@ -46,7 +58,7 @@ export class PurchaseLiquidityStrategies { //*** HELPER METHODS ***// private getPurchaseLiquidityStrategyByAlias(alias: Alias): PurchaseLiquidityStrategy { - const strategy = this.purchaseLiquidityStrategies.get(alias); + const strategy = this.strategies.get(alias); if (!strategy) throw new Error(`No PurchaseLiquidityStrategy found. Alias: ${alias}`); @@ -62,13 +74,22 @@ export class PurchaseLiquidityStrategies { private getAlias(asset: Asset): Alias { const { blockchain, category: assetCategory } = asset; - if (blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) { + if (blockchain === Blockchain.BITCOIN) return Alias.BITCOIN; + + if (blockchain === Blockchain.BINANCE_SMART_CHAIN) { + if (assetCategory === AssetCategory.CRYPTO) return Alias.BSC_CRYPTO; + if (assetCategory === AssetCategory.STOCK) return Alias.BSC_TOKEN; + } + + if (blockchain === Blockchain.DEFICHAIN) { if (assetCategory === AssetCategory.POOL_PAIR) return Alias.DEFICHAIN_POOL_PAIR; if (assetCategory === AssetCategory.STOCK) return Alias.DEFICHAIN_STOCK; if (assetCategory === AssetCategory.CRYPTO) return Alias.DEFICHAIN_CRYPTO; } - if (blockchain === Blockchain.ETHEREUM) return Alias.ETHEREUM_DEFAULT; - if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return Alias.BSC_DEFAULT; + if (blockchain === Blockchain.ETHEREUM) { + if (assetCategory === AssetCategory.CRYPTO) return Alias.ETHEREUM_CRYPTO; + if (assetCategory === AssetCategory.STOCK) return Alias.ETHEREUM_TOKEN; + } } } From ebd77b740871b264ed3038f352a74aa5edd90a8b Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 3 Oct 2022 11:15:04 +0200 Subject: [PATCH 04/30] [DEV-622] adapted DexEvmService to token purchase --- src/blockchain/shared/evm/evm-client.ts | 12 ++++- .../models/dex/services/dex-evm.service.ts | 48 +++++++++++++------ .../payout/services/payout-evm.service.ts | 2 +- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/blockchain/shared/evm/evm-client.ts b/src/blockchain/shared/evm/evm-client.ts index 69849a8f5b..3181ff2c0f 100644 --- a/src/blockchain/shared/evm/evm-client.ts +++ b/src/blockchain/shared/evm/evm-client.ts @@ -11,13 +11,17 @@ export class EvmClient { this.#address = address; } - async getBalance(): Promise { + async getNativeCryptoBalance(): Promise { const balance = await this.#provider.getBalance(this.#address); return parseFloat(ethers.utils.formatEther(balance)); } - async send(address: string, amount: number): Promise { + async getTokenBalance(tokenName: string): Promise { + return 0; + } + + async sendNativeCrypto(address: string, amount: number): Promise { const gasPrice = await this.#provider.getGasPrice(); const tx = await this.#wallet.sendTransaction({ @@ -32,6 +36,10 @@ export class EvmClient { return tx.hash; } + async sendToken(address: string, tokenName: string, amount: number): Promise { + return 'tx hash'; + } + async isTxComplete(txHash: string): Promise { const transaction = await this.getTx(txHash); diff --git a/src/payment/models/dex/services/dex-evm.service.ts b/src/payment/models/dex/services/dex-evm.service.ts index 547f6d8ebe..9b788892cb 100644 --- a/src/payment/models/dex/services/dex-evm.service.ts +++ b/src/payment/models/dex/services/dex-evm.service.ts @@ -18,29 +18,49 @@ export abstract class DexEvmService { this.#client = service.getDefaultClient(); } - async getBalance(): Promise { - return this.#client.getBalance(); + async checkCoinAvailability(amount: number): Promise { + const pendingAmount = await this.getPendingAmount(this.nativeCoin); + const availableAmount = await this.#client.getNativeCryptoBalance(); + + this.checkLiquidity(amount, pendingAmount, availableAmount, this.nativeCoin); + + return amount; } - async checkCoinAvailability(amount: number): Promise { + async checkTokenAvailability(token: string, amount: number): Promise { + const pendingAmount = await this.getPendingAmount(token); + const availableAmount = await this.#client.getTokenBalance(token); + + this.checkLiquidity(amount, pendingAmount, availableAmount, token); + + return amount; + } + + get _nativeCoin(): string { + return this.nativeCoin; + } + + //*** HELPER METHODS ***// + + private async getPendingAmount(assetName: string): Promise { const pendingOrders = (await this.liquidityOrderRepo.find({ isReady: true, isComplete: false })).filter( - (o) => o.targetAsset.dexName === this.nativeCoin && o.targetAsset.blockchain === this.blockchain, + (o) => o.targetAsset.dexName === assetName && o.targetAsset.blockchain === this.blockchain, ); - const pendingAmount = Util.sumObj(pendingOrders, 'targetAmount'); - const availableAmount = await this.getBalance(); + return Util.sumObj(pendingOrders, 'targetAmount'); + } + private checkLiquidity( + requiredAmount: number, + pendingAmount: number, + availableAmount: number, + assetName: string, + ): void { // 5% cap for unexpected meantime swaps - if (amount * 1.05 > availableAmount - pendingAmount) { + if (requiredAmount * 1.05 > availableAmount - pendingAmount) { throw new NotEnoughLiquidityException( - `Not enough liquidity of asset ${this.nativeCoin}. Trying to use ${amount} ${this.nativeCoin} worth liquidity. Available amount: ${availableAmount}. Pending amount: ${pendingAmount}`, + `Not enough liquidity of asset ${this.nativeCoin}. Trying to use ${requiredAmount} ${assetName} worth liquidity. Available amount: ${availableAmount}. Pending amount: ${pendingAmount}`, ); } - - return amount; - } - - get _nativeCoin(): string { - return this.nativeCoin; } } diff --git a/src/payment/models/payout/services/payout-evm.service.ts b/src/payment/models/payout/services/payout-evm.service.ts index 616cc3c7f7..ec67f940e2 100644 --- a/src/payment/models/payout/services/payout-evm.service.ts +++ b/src/payment/models/payout/services/payout-evm.service.ts @@ -9,7 +9,7 @@ export abstract class PayoutEvmService { } async send(address: string, amount: number): Promise { - return this.#client.send(address, amount); + return this.#client.sendNativeCrypto(address, amount); } async checkPayoutCompletion(txHash: string): Promise { From a6bbeab53e0525f6c23ebbc432d0c3f0107d4097 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 3 Oct 2022 12:30:43 +0200 Subject: [PATCH 05/30] [DEV-622] restructured payout strategies --- src/payment/models/payout/payout.module.ts | 44 +-- .../models/payout/services/payout.service.ts | 20 +- .../__tests__/payout.facade.spec.ts | 170 ++++++++++ .../__tests__/strategies.facade.spec.ts | 297 ------------------ .../payout-defichain-token.strategy.spec.ts | 4 +- .../payout-defichain.strategy.spec.ts | 4 +- .../base/defichain.strategy.ts} | 8 +- .../base/evm.strategy.ts} | 8 +- .../payout/{ => impl}/base/payout.strategy.ts | 2 +- .../bitcoin.strategy.ts} | 8 +- .../payout/impl/bsc-crypto.strategy.ts | 11 + .../payout/impl/bsc-token.strategy.ts | 11 + .../defichain-dfi.strategy.ts} | 10 +- .../defichain-token.strategy.ts} | 10 +- .../payout/impl/ethereum-crypto.strategy.ts | 11 + .../payout/impl/ethereum-token.strategy.ts | 11 + .../payout/payout-bsc-crypto.strategy.ts | 11 - .../payout/payout-bsc-token.strategy.ts | 11 - .../payout/payout-ethereum-crypto.strategy.ts | 11 - .../payout/payout-ethereum-token.strategy.ts | 11 - .../payout/strategies/payout/payout.facade.ts | 65 ++++ .../prepare/__tests__/prepare.facade.spec.ts | 125 ++++++++ .../base/evm.strategy.ts} | 6 +- .../{ => impl}/base/prepare.strategy.ts | 2 +- .../strategies/prepare/impl/bsc.strategy.ts | 10 + .../defichain.strategy.ts} | 8 +- .../prepare/impl/ethereum.strategy.ts | 10 + .../prepare/prepare-bsc.strategy.ts | 10 - .../prepare/prepare-ethereum.strategy.ts | 10 - .../strategies/prepare/prepare.facade.ts | 54 ++++ .../payout/strategies/strategies.facade.ts | 111 ------- 31 files changed, 547 insertions(+), 537 deletions(-) create mode 100644 src/payment/models/payout/strategies/__tests__/payout.facade.spec.ts delete mode 100644 src/payment/models/payout/strategies/__tests__/strategies.facade.spec.ts rename src/payment/models/payout/strategies/payout/{base/payout-defichain.strategy.ts => impl/base/defichain.strategy.ts} (93%) rename src/payment/models/payout/strategies/payout/{base/payout-evm.strategy.ts => impl/base/evm.strategy.ts} (77%) rename src/payment/models/payout/strategies/payout/{ => impl}/base/payout.strategy.ts (67%) rename src/payment/models/payout/strategies/payout/{payout-bitcoin.strategy.ts => impl/bitcoin.strategy.ts} (62%) create mode 100644 src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts create mode 100644 src/payment/models/payout/strategies/payout/impl/bsc-token.strategy.ts rename src/payment/models/payout/strategies/payout/{payout-defichain-dfi.strategy.ts => impl/defichain-dfi.strategy.ts} (77%) rename src/payment/models/payout/strategies/payout/{payout-defichain-token.strategy.ts => impl/defichain-token.strategy.ts} (87%) create mode 100644 src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts create mode 100644 src/payment/models/payout/strategies/payout/impl/ethereum-token.strategy.ts delete mode 100644 src/payment/models/payout/strategies/payout/payout-bsc-crypto.strategy.ts delete mode 100644 src/payment/models/payout/strategies/payout/payout-bsc-token.strategy.ts delete mode 100644 src/payment/models/payout/strategies/payout/payout-ethereum-crypto.strategy.ts delete mode 100644 src/payment/models/payout/strategies/payout/payout-ethereum-token.strategy.ts create mode 100644 src/payment/models/payout/strategies/payout/payout.facade.ts create mode 100644 src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts rename src/payment/models/payout/strategies/prepare/{base/prepare-evm.strategy.ts => impl/base/evm.strategy.ts} (64%) rename src/payment/models/payout/strategies/prepare/{ => impl}/base/prepare.strategy.ts (68%) create mode 100644 src/payment/models/payout/strategies/prepare/impl/bsc.strategy.ts rename src/payment/models/payout/strategies/prepare/{prepare-defichain.strategy.ts => impl/defichain.strategy.ts} (85%) create mode 100644 src/payment/models/payout/strategies/prepare/impl/ethereum.strategy.ts delete mode 100644 src/payment/models/payout/strategies/prepare/prepare-bsc.strategy.ts delete mode 100644 src/payment/models/payout/strategies/prepare/prepare-ethereum.strategy.ts create mode 100644 src/payment/models/payout/strategies/prepare/prepare.facade.ts delete mode 100644 src/payment/models/payout/strategies/strategies.facade.ts diff --git a/src/payment/models/payout/payout.module.ts b/src/payment/models/payout/payout.module.ts index 11da8b8d6d..e625f16a12 100644 --- a/src/payment/models/payout/payout.module.ts +++ b/src/payment/models/payout/payout.module.ts @@ -12,18 +12,19 @@ import { PayoutDeFiChainService } from './services/payout-defichain.service'; import { PayoutEthereumService } from './services/payout-ethereum.service'; import { PayoutLogService } from './services/payout-log.service'; import { PayoutService } from './services/payout.service'; -import { PayoutBscCryptoStrategy } from './strategies/payout/payout-bsc-crypto.strategy'; -import { PayoutDeFiChainDFIStrategy } from './strategies/payout/payout-defichain-dfi.strategy'; -import { PayoutEthereumCryptoStrategy } from './strategies/payout/payout-ethereum-crypto.strategy'; -import { PayoutDeFiChainTokenStrategy } from './strategies/payout/payout-defichain-token.strategy'; -import { PrepareBscStrategy } from './strategies/prepare/prepare-bsc.strategy'; -import { PrepareDeFiChainStrategy } from './strategies/prepare/prepare-defichain.strategy'; -import { PrepareEthereumStrategy } from './strategies/prepare/prepare-ethereum.strategy'; -import { PayoutStrategiesFacade } from './strategies/strategies.facade'; +import { PayoutStrategiesFacade } from './strategies/payout/payout.facade'; import { PayoutBitcoinService } from './services/payout-bitcoin.service'; -import { PayoutBitcoinStrategy } from './strategies/payout/payout-bitcoin.strategy'; -import { PayoutBscTokenStrategy } from './strategies/payout/payout-bsc-token.strategy'; -import { PayoutEthereumTokenStrategy } from './strategies/payout/payout-ethereum-token.strategy'; +import { PrepareStrategiesFacade } from './strategies/prepare/prepare.facade'; +import { BitcoinStrategy as BitcoinStrategyPO } from './strategies/payout/impl/bitcoin.strategy'; +import { BscCryptoStrategy as BscCryptoStrategyPO } from './strategies/payout/impl/bsc-crypto.strategy'; +import { BscTokenStrategy as BscTokenStrategyPO } from './strategies/payout/impl/bsc-token.strategy'; +import { DeFiChainDfiStrategy as DeFiChainDfiStrategyPO } from './strategies/payout/impl/defichain-dfi.strategy'; +import { DeFiChainTokenStrategy as DeFiChainTokenStrategyPO } from './strategies/payout/impl/defichain-token.strategy'; +import { EthereumCryptoStrategy as EthereumCryptoStrategyPO } from './strategies/payout/impl/ethereum-crypto.strategy'; +import { EthereumTokenStrategy as EthereumTokenStrategyPO } from './strategies/payout/impl/ethereum-token.strategy'; +import { BscStrategy as BscStrategyPR } from './strategies/prepare/impl/bsc.strategy'; +import { DeFiChainStrategy as DeFiChainStrategyPR } from './strategies/prepare/impl/defichain.strategy'; +import { EthereumStrategy as EthereumStrategyPR } from './strategies/prepare/impl/ethereum.strategy'; @Module({ imports: [ @@ -43,17 +44,18 @@ import { PayoutEthereumTokenStrategy } from './strategies/payout/payout-ethereum PayoutDeFiChainService, PayoutEthereumService, PayoutBscService, - PayoutBitcoinStrategy, - PayoutBscCryptoStrategy, - PayoutBscTokenStrategy, - PayoutDeFiChainDFIStrategy, - PayoutDeFiChainTokenStrategy, - PayoutEthereumCryptoStrategy, - PayoutEthereumTokenStrategy, - PrepareDeFiChainStrategy, - PrepareEthereumStrategy, - PrepareBscStrategy, PayoutStrategiesFacade, + PrepareStrategiesFacade, + BitcoinStrategyPO, + BscCryptoStrategyPO, + BscTokenStrategyPO, + DeFiChainDfiStrategyPO, + DeFiChainTokenStrategyPO, + EthereumCryptoStrategyPO, + EthereumTokenStrategyPO, + BscStrategyPR, + DeFiChainStrategyPR, + EthereumStrategyPR, ], exports: [PayoutService], }) diff --git a/src/payment/models/payout/services/payout.service.ts b/src/payment/models/payout/services/payout.service.ts index d8e3ea7270..76d9286592 100644 --- a/src/payment/models/payout/services/payout.service.ts +++ b/src/payment/models/payout/services/payout.service.ts @@ -6,17 +6,19 @@ import { PayoutOrderFactory } from '../factories/payout-order.factory'; import { PayoutOrderRepository } from '../repositories/payout-order.repository'; import { DuplicatedEntryException } from '../exceptions/duplicated-entry.exception'; import { MailService } from 'src/shared/services/mail.service'; -import { PayoutStrategiesFacade, PayoutStrategyAlias } from '../strategies/strategies.facade'; +import { PayoutStrategiesFacade, PayoutStrategyAlias } from '../strategies/payout/payout.facade'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; import { PayoutLogService } from './payout-log.service'; import { PayoutRequest } from '../interfaces'; +import { PrepareStrategiesFacade } from '../strategies/prepare/prepare.facade'; @Injectable() export class PayoutService { private readonly processOrdersLock = new Lock(1800); constructor( - private readonly strategies: PayoutStrategiesFacade, + private readonly payoutStrategies: PayoutStrategiesFacade, + private readonly prepareStrategies: PrepareStrategiesFacade, private readonly logs: PayoutLogService, private readonly mailService: MailService, private readonly payoutOrderRepo: PayoutOrderRepository, @@ -86,7 +88,7 @@ export class PayoutService { const confirmedOrders = []; for (const order of orders) { - const strategy = this.strategies.getPrepareStrategy(order.asset); + const strategy = this.prepareStrategies.getPrepareStrategy(order.asset); try { await strategy.checkPreparationCompletion(order); @@ -105,7 +107,7 @@ export class PayoutService { const confirmedOrders = []; for (const order of orders) { - const strategy = this.strategies.getPayoutStrategy(order.asset); + const strategy = this.payoutStrategies.getPayoutStrategy(order.asset); try { await strategy.checkPayoutCompletion(order); @@ -123,7 +125,7 @@ export class PayoutService { const confirmedOrders = []; for (const order of orders) { - const strategy = this.strategies.getPrepareStrategy(order.asset); + const strategy = this.prepareStrategies.getPrepareStrategy(order.asset); try { await strategy.preparePayout(order); @@ -146,10 +148,10 @@ export class PayoutService { (o) => o.asset.blockchain === Blockchain.BINANCE_SMART_CHAIN && o.asset.dexName === 'BNB', ); - const dfiStrategy = this.strategies.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_DFI); - const tokenStrategy = this.strategies.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_TOKEN); - const ethStrategy = this.strategies.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_DEFAULT); - const bnbStrategy = this.strategies.getPayoutStrategy(PayoutStrategyAlias.BSC_DEFAULT); + const dfiStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_DFI); + const tokenStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_TOKEN); + const ethStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_DEFAULT); + const bnbStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.BSC_DEFAULT); await dfiStrategy.doPayout(dfiOrders); await tokenStrategy.doPayout(tokenOrders); diff --git a/src/payment/models/payout/strategies/__tests__/payout.facade.spec.ts b/src/payment/models/payout/strategies/__tests__/payout.facade.spec.ts new file mode 100644 index 0000000000..cc114b4260 --- /dev/null +++ b/src/payment/models/payout/strategies/__tests__/payout.facade.spec.ts @@ -0,0 +1,170 @@ +import { mock } from 'jest-mock-extended'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { DexService } from 'src/payment/models/dex/services/dex.service'; +import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; +import { MailService } from 'src/shared/services/mail.service'; +import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; +import { PayoutBscService } from '../../services/payout-bsc.service'; +import { PayoutDeFiChainService } from '../../services/payout-defichain.service'; +import { PayoutEthereumService } from '../../services/payout-ethereum.service'; +import { BscCryptoStrategy } from '../payout/impl/bsc-crypto.strategy'; +import { DeFiChainDfiStrategy } from '../payout/impl/defichain-dfi.strategy'; +import { DeFiChainTokenStrategy } from '../payout/impl/defichain-token.strategy'; +import { EthereumCryptoStrategy } from '../payout/impl/ethereum-crypto.strategy'; +import { PayoutStrategiesFacade, PayoutStrategyAlias } from '../payout/payout.facade'; + +describe('PayoutStrategiesFacade', () => { + let dfi: DeFiChainDfiStrategy; + let token: DeFiChainTokenStrategy; + let ethCrypto: EthereumCryptoStrategy; + let bscCrypto: BscCryptoStrategy; + + let facade: PayoutStrategiesFacadeWrapper; + + beforeEach(() => { + dfi = new DeFiChainDfiStrategy(mock(), mock(), mock()); + token = new DeFiChainTokenStrategy( + mock(), + mock(), + mock(), + mock(), + ); + ethCrypto = new EthereumCryptoStrategy(mock(), mock()); + bscCrypto = new BscCryptoStrategy(mock(), mock()); + + facade = new PayoutStrategiesFacadeWrapper(dfi, token, ethCrypto, bscCrypto); + }); + + describe('#constructor(...)', () => { + it('adds all payoutStrategies to a map', () => { + expect([...facade.getPayoutStrategies().entries()].length).toBe(4); + }); + + it('sets all required payoutStrategies aliases', () => { + const aliases = [...facade.getPayoutStrategies().keys()]; + + expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_DFI)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_TOKEN)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.ETHEREUM_DEFAULT)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.BSC_DEFAULT)).toBe(true); + }); + + it('assigns proper payoutStrategies to aliases', () => { + expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.DEFICHAIN_DFI)).toBeInstanceOf(DeFiChainDfiStrategy); + + expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.DEFICHAIN_TOKEN)).toBeInstanceOf( + DeFiChainTokenStrategy, + ); + + expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.ETHEREUM_DEFAULT)).toBeInstanceOf( + EthereumCryptoStrategy, + ); + + expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.BSC_DEFAULT)).toBeInstanceOf(BscCryptoStrategy); + }); + }); + + describe('#getPayoutStrategy(...)', () => { + describe('getting strategy by Asset', () => { + it('gets ETHEREUM_DEFAULT strategy', () => { + const strategy = facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); + + expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + }); + + it('gets BSC_DEFAULT strategy', () => { + const strategy = facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN })); + + expect(strategy).toBeInstanceOf(BscCryptoStrategy); + }); + + it('gets DEFICHAIN_DFI strategy', () => { + const strategy = facade.getPayoutStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, dexName: 'DFI' }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainDfiStrategy); + }); + + it('gets DEFICHAIN_TOKEN strategy for DEFICHAIN', () => { + const strategy = facade.getPayoutStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, dexName: 'non-DFI' }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainTokenStrategy); + }); + + it('gets DEFICHAIN_TOKEN strategy for BITCOIN', () => { + const strategy = facade.getPayoutStrategy( + createCustomAsset({ blockchain: Blockchain.BITCOIN, dexName: 'non-DFI' }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainTokenStrategy); + }); + + it('fails to get strategy for non-supported Blockchain', () => { + const testCall = () => + facade.getPayoutStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No PayoutStrategy found. Alias: undefined'); + }); + + it('fails to get strategy for DFI on Bitcoin blockchain', () => { + const testCall = () => + facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.BITCOIN, dexName: 'DFI' })); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No PayoutStrategy found. Alias: undefined'); + }); + }); + + describe('getting strategy by Alias', () => { + it('gets ETHEREUM_DEFAULT strategy', () => { + const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_DEFAULT); + + expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + }); + + it('gets BSC_DEFAULT strategy', () => { + const strategyCrypto = facade.getPayoutStrategy(PayoutStrategyAlias.BSC_DEFAULT); + + expect(strategyCrypto).toBeInstanceOf(BscCryptoStrategy); + }); + + it('gets DEFICHAIN_DFI strategy', () => { + const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_DFI); + + expect(strategy).toBeInstanceOf(DeFiChainDfiStrategy); + }); + + it('gets DEFICHAIN_TOKEN strategy', () => { + const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_TOKEN); + + expect(strategy).toBeInstanceOf(DeFiChainTokenStrategy); + }); + + it('fails to get strategy for non-supported Alias', () => { + const testCall = () => facade.getPayoutStrategy('NonExistingAlias' as PayoutStrategyAlias); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No PayoutStrategy found. Alias: NonExistingAlias'); + }); + }); + }); +}); + +class PayoutStrategiesFacadeWrapper extends PayoutStrategiesFacade { + constructor( + payoutDFIStrategy: DeFiChainDfiStrategy, + payoutTokenStrategy: DeFiChainTokenStrategy, + payoutETHStrategy: EthereumCryptoStrategy, + payoutBSCStrategy: BscCryptoStrategy, + ) { + super(payoutDFIStrategy, payoutTokenStrategy, payoutETHStrategy, payoutBSCStrategy); + } + + getPayoutStrategies() { + return this.strategies; + } +} diff --git a/src/payment/models/payout/strategies/__tests__/strategies.facade.spec.ts b/src/payment/models/payout/strategies/__tests__/strategies.facade.spec.ts deleted file mode 100644 index 1dca74caa9..0000000000 --- a/src/payment/models/payout/strategies/__tests__/strategies.facade.spec.ts +++ /dev/null @@ -1,297 +0,0 @@ -import { mock } from 'jest-mock-extended'; -import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { DexService } from 'src/payment/models/dex/services/dex.service'; -import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; -import { MailService } from 'src/shared/services/mail.service'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PayoutBscService } from '../../services/payout-bsc.service'; -import { PayoutDeFiChainService } from '../../services/payout-defichain.service'; -import { PayoutEthereumService } from '../../services/payout-ethereum.service'; -import { PayoutBscCryptoStrategy } from '../payout/payout-bsc-crypto.strategy'; -import { PayoutDeFiChainDFIStrategy } from '../payout/payout-defichain-dfi.strategy'; -import { PayoutDeFiChainTokenStrategy } from '../payout/payout-defichain-token.strategy'; -import { PayoutEthereumCryptoStrategy } from '../payout/payout-ethereum-crypto.strategy'; -import { PrepareBscStrategy } from '../prepare/prepare-bsc.strategy'; -import { PrepareDeFiChainStrategy } from '../prepare/prepare-defichain.strategy'; -import { PrepareEthereumStrategy } from '../prepare/prepare-ethereum.strategy'; -import { PayoutStrategiesFacade, PayoutStrategyAlias, PrepareStrategyAlias } from '../strategies.facade'; - -describe('PayoutStrategiesFacade', () => { - let payoutDFIStrategy: PayoutDeFiChainDFIStrategy; - let payoutTokenStrategy: PayoutDeFiChainTokenStrategy; - let payoutETHStrategy: PayoutEthereumCryptoStrategy; - let payoutBSCStrategy: PayoutBscCryptoStrategy; - let prepareOnDefichainStrategy: PrepareDeFiChainStrategy; - let prepareOnEthereumStrategy: PrepareEthereumStrategy; - let prepareOnBscStrategy: PrepareBscStrategy; - - let facade: PayoutStrategiesFacadeWrapper; - - beforeEach(() => { - payoutDFIStrategy = new PayoutDeFiChainDFIStrategy( - mock(), - mock(), - mock(), - ); - payoutTokenStrategy = new PayoutDeFiChainTokenStrategy( - mock(), - mock(), - mock(), - mock(), - ); - payoutETHStrategy = new PayoutEthereumCryptoStrategy(mock(), mock()); - payoutBSCStrategy = new PayoutBscCryptoStrategy(mock(), mock()); - prepareOnDefichainStrategy = new PrepareDeFiChainStrategy( - mock(), - mock(), - mock(), - ); - prepareOnEthereumStrategy = new PrepareEthereumStrategy(mock()); - prepareOnBscStrategy = new PrepareBscStrategy(mock()); - - facade = new PayoutStrategiesFacadeWrapper( - payoutDFIStrategy, - payoutTokenStrategy, - payoutETHStrategy, - payoutBSCStrategy, - prepareOnDefichainStrategy, - prepareOnEthereumStrategy, - prepareOnBscStrategy, - ); - }); - - describe('#constructor(...)', () => { - it('adds all payoutStrategies to a map', () => { - expect([...facade.getPayoutStrategies().entries()].length).toBe(4); - }); - - it('sets all required payoutStrategies aliases', () => { - const aliases = [...facade.getPayoutStrategies().keys()]; - - expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_DFI)).toBe(true); - expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_TOKEN)).toBe(true); - expect(aliases.includes(PayoutStrategyAlias.ETHEREUM_DEFAULT)).toBe(true); - expect(aliases.includes(PayoutStrategyAlias.BSC_DEFAULT)).toBe(true); - }); - - it('assigns proper payoutStrategies to aliases', () => { - expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.DEFICHAIN_DFI)).toBeInstanceOf( - PayoutDeFiChainDFIStrategy, - ); - - expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.DEFICHAIN_TOKEN)).toBeInstanceOf( - PayoutDeFiChainTokenStrategy, - ); - - expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.ETHEREUM_DEFAULT)).toBeInstanceOf( - PayoutEthereumCryptoStrategy, - ); - - expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.BSC_DEFAULT)).toBeInstanceOf(PayoutBscCryptoStrategy); - }); - - it('adds all prepareStrategies to a map', () => { - expect([...facade.getPrepareStrategies().entries()].length).toBe(3); - }); - - it('sets all required prepareStrategies aliases', () => { - const aliases = [...facade.getPrepareStrategies().keys()]; - - expect(aliases.includes(PrepareStrategyAlias.DEFICHAIN)).toBe(true); - expect(aliases.includes(PrepareStrategyAlias.ETHEREUM)).toBe(true); - expect(aliases.includes(PrepareStrategyAlias.BSC)).toBe(true); - }); - - it('assigns proper prepareStrategies to aliases', () => { - expect(facade.getPrepareStrategies().get(PrepareStrategyAlias.DEFICHAIN)).toBeInstanceOf( - PrepareDeFiChainStrategy, - ); - - expect(facade.getPrepareStrategies().get(PrepareStrategyAlias.ETHEREUM)).toBeInstanceOf(PrepareEthereumStrategy); - - expect(facade.getPrepareStrategies().get(PrepareStrategyAlias.BSC)).toBeInstanceOf(PrepareBscStrategy); - }); - }); - - describe('#getPayoutStrategy(...)', () => { - describe('getting strategy by Asset', () => { - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); - - expect(strategy).toBeInstanceOf(PayoutEthereumCryptoStrategy); - }); - - it('gets BSC_DEFAULT strategy', () => { - const strategy = facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN })); - - expect(strategy).toBeInstanceOf(PayoutBscCryptoStrategy); - }); - - it('gets DEFICHAIN_DFI strategy', () => { - const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, dexName: 'DFI' }), - ); - - expect(strategy).toBeInstanceOf(PayoutDeFiChainDFIStrategy); - }); - - it('gets DEFICHAIN_TOKEN strategy for DEFICHAIN', () => { - const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, dexName: 'non-DFI' }), - ); - - expect(strategy).toBeInstanceOf(PayoutDeFiChainTokenStrategy); - }); - - it('gets DEFICHAIN_TOKEN strategy for BITCOIN', () => { - const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.BITCOIN, dexName: 'non-DFI' }), - ); - - expect(strategy).toBeInstanceOf(PayoutDeFiChainTokenStrategy); - }); - - it('fails to get strategy for non-supported Blockchain', () => { - const testCall = () => - facade.getPayoutStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PayoutStrategy found. Alias: undefined'); - }); - - it('fails to get strategy for DFI on Bitcoin blockchain', () => { - const testCall = () => - facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.BITCOIN, dexName: 'DFI' })); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PayoutStrategy found. Alias: undefined'); - }); - }); - - describe('getting strategy by Alias', () => { - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_DEFAULT); - - expect(strategy).toBeInstanceOf(PayoutEthereumCryptoStrategy); - }); - - it('gets BSC_DEFAULT strategy', () => { - const strategyCrypto = facade.getPayoutStrategy(PayoutStrategyAlias.BSC_DEFAULT); - - expect(strategyCrypto).toBeInstanceOf(PayoutBscCryptoStrategy); - }); - - it('gets DEFICHAIN_DFI strategy', () => { - const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_DFI); - - expect(strategy).toBeInstanceOf(PayoutDeFiChainDFIStrategy); - }); - - it('gets DEFICHAIN_TOKEN strategy', () => { - const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_TOKEN); - - expect(strategy).toBeInstanceOf(PayoutDeFiChainTokenStrategy); - }); - - it('fails to get strategy for non-supported Alias', () => { - const testCall = () => facade.getPayoutStrategy('NonExistingAlias' as PayoutStrategyAlias); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PayoutStrategy found. Alias: NonExistingAlias'); - }); - }); - }); - - describe('#getPrepareStrategy(...)', () => { - describe('getting strategy by Asset', () => { - it('gets ETHEREUM strategy', () => { - const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); - - expect(strategy).toBeInstanceOf(PrepareEthereumStrategy); - }); - - it('gets BSC strategy', () => { - const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN })); - - expect(strategy).toBeInstanceOf(PrepareBscStrategy); - }); - - it('gets DEFICHAIN strategy for DEFICHAIN', () => { - const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.DEFICHAIN })); - - expect(strategy).toBeInstanceOf(PrepareDeFiChainStrategy); - }); - - it('gets DEFICHAIN strategy for BITCOIN', () => { - const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.BITCOIN })); - - expect(strategy).toBeInstanceOf(PrepareDeFiChainStrategy); - }); - - it('fails to get strategy for non-supported Blockchain', () => { - const testCall = () => - facade.getPrepareStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PrepareStrategy found. Alias: undefined'); - }); - }); - - describe('getting strategy by Alias', () => { - it('gets DEFICHAIN strategy', () => { - const strategy = facade.getPrepareStrategy(PrepareStrategyAlias.DEFICHAIN); - - expect(strategy).toBeInstanceOf(PrepareDeFiChainStrategy); - }); - - it('gets ETHEREUM strategy', () => { - const strategyCrypto = facade.getPrepareStrategy(PrepareStrategyAlias.ETHEREUM); - - expect(strategyCrypto).toBeInstanceOf(PrepareEthereumStrategy); - }); - - it('gets BSC strategy', () => { - const strategyCrypto = facade.getPrepareStrategy(PrepareStrategyAlias.BSC); - - expect(strategyCrypto).toBeInstanceOf(PrepareBscStrategy); - }); - - it('fails to get strategy for non-supported Alias', () => { - const testCall = () => facade.getPrepareStrategy('NonExistingAlias' as PrepareStrategyAlias); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PrepareStrategy found. Alias: NonExistingAlias'); - }); - }); - }); -}); - -class PayoutStrategiesFacadeWrapper extends PayoutStrategiesFacade { - constructor( - payoutDFIStrategy: PayoutDeFiChainDFIStrategy, - payoutTokenStrategy: PayoutDeFiChainTokenStrategy, - payoutETHStrategy: PayoutEthereumCryptoStrategy, - payoutBSCStrategy: PayoutBscCryptoStrategy, - prepareOnDefichainStrategy: PrepareDeFiChainStrategy, - prepareOnEthereumStrategy: PrepareEthereumStrategy, - prepareOnBscStrategy: PrepareBscStrategy, - ) { - super( - payoutDFIStrategy, - payoutTokenStrategy, - payoutETHStrategy, - payoutBSCStrategy, - prepareOnDefichainStrategy, - prepareOnEthereumStrategy, - prepareOnBscStrategy, - ); - } - - getPayoutStrategies() { - return this.payoutStrategies; - } - - getPrepareStrategies() { - return this.prepareStrategies; - } -} diff --git a/src/payment/models/payout/strategies/payout/__tests__/payout-defichain-token.strategy.spec.ts b/src/payment/models/payout/strategies/payout/__tests__/payout-defichain-token.strategy.spec.ts index c4e8531060..1418ccc923 100644 --- a/src/payment/models/payout/strategies/payout/__tests__/payout-defichain-token.strategy.spec.ts +++ b/src/payment/models/payout/strategies/payout/__tests__/payout-defichain-token.strategy.spec.ts @@ -9,7 +9,7 @@ import { } from '../../../entities/__mocks__/payout-order.entity.mock'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; -import { PayoutDeFiChainTokenStrategy } from '../payout-defichain-token.strategy'; +import { DeFiChainTokenStrategy } from '../impl/defichain-token.strategy'; describe('PayoutDeFiChainTokenStrategy', () => { let strategy: PayoutDeFiChainTokenStrategyWrapper; @@ -66,7 +66,7 @@ describe('PayoutDeFiChainTokenStrategy', () => { }); }); -class PayoutDeFiChainTokenStrategyWrapper extends PayoutDeFiChainTokenStrategy { +class PayoutDeFiChainTokenStrategyWrapper extends DeFiChainTokenStrategy { constructor( mailService: MailService, dexService: DexService, diff --git a/src/payment/models/payout/strategies/payout/__tests__/payout-defichain.strategy.spec.ts b/src/payment/models/payout/strategies/payout/__tests__/payout-defichain.strategy.spec.ts index 742de4c8b9..1846170b73 100644 --- a/src/payment/models/payout/strategies/payout/__tests__/payout-defichain.strategy.spec.ts +++ b/src/payment/models/payout/strategies/payout/__tests__/payout-defichain.strategy.spec.ts @@ -8,7 +8,7 @@ import { } from '../../../entities/__mocks__/payout-order.entity.mock'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; -import { PayoutDeFiChainStrategy } from '../base/payout-defichain.strategy'; +import { DeFiChainStrategy } from '../impl/base/defichain.strategy'; describe('PayoutDeFiChainStrategy', () => { let strategy: PayoutDeFiChainStrategyWrapper; @@ -250,7 +250,7 @@ describe('PayoutDeFiChainStrategy', () => { }); }); -class PayoutDeFiChainStrategyWrapper extends PayoutDeFiChainStrategy { +class PayoutDeFiChainStrategyWrapper extends DeFiChainStrategy { constructor( mailService: MailService, payoutOrderRepo: PayoutOrderRepository, diff --git a/src/payment/models/payout/strategies/payout/base/payout-defichain.strategy.ts b/src/payment/models/payout/strategies/payout/impl/base/defichain.strategy.ts similarity index 93% rename from src/payment/models/payout/strategies/payout/base/payout-defichain.strategy.ts rename to src/payment/models/payout/strategies/payout/impl/base/defichain.strategy.ts index 9f3efdc3a8..90698b8f4f 100644 --- a/src/payment/models/payout/strategies/payout/base/payout-defichain.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/base/defichain.strategy.ts @@ -1,11 +1,11 @@ import { MailService } from 'src/shared/services/mail.service'; import { Util } from 'src/shared/util'; -import { PayoutOrder, PayoutOrderContext } from '../../../entities/payout-order.entity'; -import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; -import { PayoutDeFiChainService, PayoutGroup } from '../../../services/payout-defichain.service'; +import { PayoutOrder, PayoutOrderContext } from '../../../../entities/payout-order.entity'; +import { PayoutOrderRepository } from '../../../../repositories/payout-order.repository'; +import { PayoutDeFiChainService, PayoutGroup } from '../../../../services/payout-defichain.service'; import { PayoutStrategy } from './payout.strategy'; -export abstract class PayoutDeFiChainStrategy implements PayoutStrategy { +export abstract class DeFiChainStrategy implements PayoutStrategy { constructor( protected readonly mailService: MailService, protected readonly payoutOrderRepo: PayoutOrderRepository, diff --git a/src/payment/models/payout/strategies/payout/base/payout-evm.strategy.ts b/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts similarity index 77% rename from src/payment/models/payout/strategies/payout/base/payout-evm.strategy.ts rename to src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts index 4f09cf7354..c6302f9df6 100644 --- a/src/payment/models/payout/strategies/payout/base/payout-evm.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts @@ -1,9 +1,9 @@ -import { PayoutOrder } from '../../../entities/payout-order.entity'; -import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; -import { PayoutEvmService } from '../../../services/payout-evm.service'; +import { PayoutOrder } from '../../../../entities/payout-order.entity'; +import { PayoutOrderRepository } from '../../../../repositories/payout-order.repository'; +import { PayoutEvmService } from '../../../../services/payout-evm.service'; import { PayoutStrategy } from './payout.strategy'; -export abstract class PayoutEvmStrategy implements PayoutStrategy { +export abstract class EvmStrategy implements PayoutStrategy { constructor( protected readonly payoutEvmService: PayoutEvmService, protected readonly payoutOrderRepo: PayoutOrderRepository, diff --git a/src/payment/models/payout/strategies/payout/base/payout.strategy.ts b/src/payment/models/payout/strategies/payout/impl/base/payout.strategy.ts similarity index 67% rename from src/payment/models/payout/strategies/payout/base/payout.strategy.ts rename to src/payment/models/payout/strategies/payout/impl/base/payout.strategy.ts index 2111933bee..7fbada9cfd 100644 --- a/src/payment/models/payout/strategies/payout/base/payout.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/base/payout.strategy.ts @@ -1,4 +1,4 @@ -import { PayoutOrder } from '../../../entities/payout-order.entity'; +import { PayoutOrder } from '../../../../entities/payout-order.entity'; export interface PayoutStrategy { doPayout(orders: PayoutOrder[]): Promise; diff --git a/src/payment/models/payout/strategies/payout/payout-bitcoin.strategy.ts b/src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts similarity index 62% rename from src/payment/models/payout/strategies/payout/payout-bitcoin.strategy.ts rename to src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts index 8a20d38bf4..17563d20a4 100644 --- a/src/payment/models/payout/strategies/payout/payout-bitcoin.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts @@ -1,11 +1,11 @@ import { Injectable } from '@nestjs/common'; -import { PayoutOrder } from '../../entities/payout-order.entity'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PayoutBitcoinService } from '../../services/payout-bitcoin.service'; +import { PayoutOrder } from '../../../entities/payout-order.entity'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutBitcoinService } from '../../../services/payout-bitcoin.service'; import { PayoutStrategy } from './base/payout.strategy'; @Injectable() -export class PayoutBitcoinStrategy implements PayoutStrategy { +export class BitcoinStrategy implements PayoutStrategy { constructor( protected readonly bitcoinService: PayoutBitcoinService, protected readonly payoutOrderRepo: PayoutOrderRepository, diff --git a/src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts b/src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts new file mode 100644 index 0000000000..4f4ad22fcd --- /dev/null +++ b/src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutBscService } from '../../../services/payout-bsc.service'; +import { EvmStrategy } from './base/evm.strategy'; + +@Injectable() +export class BscCryptoStrategy extends EvmStrategy { + constructor(bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { + super(bscService, payoutOrderRepo); + } +} diff --git a/src/payment/models/payout/strategies/payout/impl/bsc-token.strategy.ts b/src/payment/models/payout/strategies/payout/impl/bsc-token.strategy.ts new file mode 100644 index 0000000000..800f4ba111 --- /dev/null +++ b/src/payment/models/payout/strategies/payout/impl/bsc-token.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutBscService } from '../../../services/payout-bsc.service'; +import { EvmStrategy } from './base/evm.strategy'; + +@Injectable() +export class BscTokenStrategy extends EvmStrategy { + constructor(bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { + super(bscService, payoutOrderRepo); + } +} diff --git a/src/payment/models/payout/strategies/payout/payout-defichain-dfi.strategy.ts b/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts similarity index 77% rename from src/payment/models/payout/strategies/payout/payout-defichain-dfi.strategy.ts rename to src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts index c4f57b12b3..b6201a1042 100644 --- a/src/payment/models/payout/strategies/payout/payout-defichain-dfi.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts @@ -1,12 +1,12 @@ import { Injectable } from '@nestjs/common'; import { MailService } from 'src/shared/services/mail.service'; -import { PayoutOrder, PayoutOrderContext } from '../../entities/payout-order.entity'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PayoutDeFiChainService } from '../../services/payout-defichain.service'; -import { PayoutDeFiChainStrategy } from './base/payout-defichain.strategy'; +import { PayoutOrderContext, PayoutOrder } from '../../../entities/payout-order.entity'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; +import { DeFiChainStrategy } from './base/defichain.strategy'; @Injectable() -export class PayoutDeFiChainDFIStrategy extends PayoutDeFiChainStrategy { +export class DeFiChainDfiStrategy extends DeFiChainStrategy { constructor( mailService: MailService, protected readonly defichainService: PayoutDeFiChainService, diff --git a/src/payment/models/payout/strategies/payout/payout-defichain-token.strategy.ts b/src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts similarity index 87% rename from src/payment/models/payout/strategies/payout/payout-defichain-token.strategy.ts rename to src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts index 926dd7c58c..2e302d1842 100644 --- a/src/payment/models/payout/strategies/payout/payout-defichain-token.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts @@ -1,15 +1,15 @@ import { Injectable } from '@nestjs/common'; import { DexService } from 'src/payment/models/dex/services/dex.service'; import { MailService } from 'src/shared/services/mail.service'; -import { PayoutOrderContext, PayoutOrder } from '../../entities/payout-order.entity'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PayoutDeFiChainService } from '../../services/payout-defichain.service'; -import { PayoutDeFiChainStrategy } from './base/payout-defichain.strategy'; +import { PayoutOrderContext, PayoutOrder } from '../../../entities/payout-order.entity'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; +import { DeFiChainStrategy } from './base/defichain.strategy'; type TokenName = string; @Injectable() -export class PayoutDeFiChainTokenStrategy extends PayoutDeFiChainStrategy { +export class DeFiChainTokenStrategy extends DeFiChainStrategy { constructor( mailService: MailService, private readonly dexService: DexService, diff --git a/src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts b/src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts new file mode 100644 index 0000000000..5d9d9b0582 --- /dev/null +++ b/src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutEthereumService } from '../../../services/payout-ethereum.service'; +import { EvmStrategy } from './base/evm.strategy'; + +@Injectable() +export class EthereumCryptoStrategy extends EvmStrategy { + constructor(ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { + super(ethereumService, payoutOrderRepo); + } +} diff --git a/src/payment/models/payout/strategies/payout/impl/ethereum-token.strategy.ts b/src/payment/models/payout/strategies/payout/impl/ethereum-token.strategy.ts new file mode 100644 index 0000000000..eac63af65e --- /dev/null +++ b/src/payment/models/payout/strategies/payout/impl/ethereum-token.strategy.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutEthereumService } from '../../../services/payout-ethereum.service'; +import { EvmStrategy } from './base/evm.strategy'; + +@Injectable() +export class EthereumTokenStrategy extends EvmStrategy { + constructor(ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { + super(ethereumService, payoutOrderRepo); + } +} diff --git a/src/payment/models/payout/strategies/payout/payout-bsc-crypto.strategy.ts b/src/payment/models/payout/strategies/payout/payout-bsc-crypto.strategy.ts deleted file mode 100644 index eee1edc2f6..0000000000 --- a/src/payment/models/payout/strategies/payout/payout-bsc-crypto.strategy.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PayoutBscService } from '../../services/payout-bsc.service'; -import { PayoutEvmStrategy } from './base/payout-evm.strategy'; - -@Injectable() -export class PayoutBscCryptoStrategy extends PayoutEvmStrategy { - constructor(bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { - super(bscService, payoutOrderRepo); - } -} diff --git a/src/payment/models/payout/strategies/payout/payout-bsc-token.strategy.ts b/src/payment/models/payout/strategies/payout/payout-bsc-token.strategy.ts deleted file mode 100644 index b976cd66ae..0000000000 --- a/src/payment/models/payout/strategies/payout/payout-bsc-token.strategy.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PayoutBscService } from '../../services/payout-bsc.service'; -import { PayoutEvmStrategy } from './base/payout-evm.strategy'; - -@Injectable() -export class PayoutBscTokenStrategy extends PayoutEvmStrategy { - constructor(bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { - super(bscService, payoutOrderRepo); - } -} diff --git a/src/payment/models/payout/strategies/payout/payout-ethereum-crypto.strategy.ts b/src/payment/models/payout/strategies/payout/payout-ethereum-crypto.strategy.ts deleted file mode 100644 index 9296d038f9..0000000000 --- a/src/payment/models/payout/strategies/payout/payout-ethereum-crypto.strategy.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PayoutEthereumService } from '../../services/payout-ethereum.service'; -import { PayoutEvmStrategy } from './base/payout-evm.strategy'; - -@Injectable() -export class PayoutEthereumCryptoStrategy extends PayoutEvmStrategy { - constructor(ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { - super(ethereumService, payoutOrderRepo); - } -} diff --git a/src/payment/models/payout/strategies/payout/payout-ethereum-token.strategy.ts b/src/payment/models/payout/strategies/payout/payout-ethereum-token.strategy.ts deleted file mode 100644 index 66aa1c426c..0000000000 --- a/src/payment/models/payout/strategies/payout/payout-ethereum-token.strategy.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PayoutEthereumService } from '../../services/payout-ethereum.service'; -import { PayoutEvmStrategy } from './base/payout-evm.strategy'; - -@Injectable() -export class PayoutEthereumTokenStrategy extends PayoutEvmStrategy { - constructor(ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { - super(ethereumService, payoutOrderRepo); - } -} diff --git a/src/payment/models/payout/strategies/payout/payout.facade.ts b/src/payment/models/payout/strategies/payout/payout.facade.ts new file mode 100644 index 0000000000..9fc1167983 --- /dev/null +++ b/src/payment/models/payout/strategies/payout/payout.facade.ts @@ -0,0 +1,65 @@ +import { Injectable } from '@nestjs/common'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { Asset } from 'src/shared/models/asset/asset.entity'; +import { PayoutStrategy } from './impl/base/payout.strategy'; +import { BscCryptoStrategy } from './impl/bsc-crypto.strategy'; +import { DeFiChainDfiStrategy } from './impl/defichain-dfi.strategy'; +import { DeFiChainTokenStrategy } from './impl/defichain-token.strategy'; +import { EthereumCryptoStrategy } from './impl/ethereum-crypto.strategy'; + +enum Alias { + DEFICHAIN_DFI = 'DeFiChainDFI', + DEFICHAIN_TOKEN = 'DeFiChainToken', + ETHEREUM_DEFAULT = 'Ethereum', + BSC_DEFAULT = 'BscDefault', +} + +export { Alias as PayoutStrategyAlias }; + +@Injectable() +export class PayoutStrategiesFacade { + protected readonly strategies: Map = new Map(); + + constructor( + deFiChainDfi: DeFiChainDfiStrategy, + deFiChainToken: DeFiChainTokenStrategy, + ethereumCrypto: EthereumCryptoStrategy, + bscCrypto: BscCryptoStrategy, + ) { + this.strategies.set(Alias.DEFICHAIN_DFI, deFiChainDfi); + this.strategies.set(Alias.DEFICHAIN_TOKEN, deFiChainToken); + this.strategies.set(Alias.ETHEREUM_DEFAULT, ethereumCrypto); + this.strategies.set(Alias.BSC_DEFAULT, bscCrypto); + } + + getPayoutStrategy(criteria: Asset | Alias): PayoutStrategy { + return criteria instanceof Asset ? this.getByAsset(criteria) : this.getByAlias(criteria); + } + + //*** HELPER METHODS ***// + + private getByAlias(alias: Alias): PayoutStrategy { + const strategy = this.strategies.get(alias); + + if (!strategy) throw new Error(`No PayoutStrategy found. Alias: ${alias}`); + + return strategy; + } + + private getByAsset(asset: Asset): PayoutStrategy { + const alias = this.getAlias(asset); + + return this.getByAlias(alias); + } + + private getAlias(asset: Asset): Alias { + const { blockchain, dexName: assetName } = asset; + + if (blockchain === Blockchain.ETHEREUM) return Alias.ETHEREUM_DEFAULT; + if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return Alias.BSC_DEFAULT; + if (blockchain === Blockchain.DEFICHAIN && assetName === 'DFI') return Alias.DEFICHAIN_DFI; + if ((blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) && assetName !== 'DFI') { + return Alias.DEFICHAIN_TOKEN; + } + } +} diff --git a/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts b/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts new file mode 100644 index 0000000000..4b257f9568 --- /dev/null +++ b/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts @@ -0,0 +1,125 @@ +import { mock } from 'jest-mock-extended'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { DexService } from 'src/payment/models/dex/services/dex.service'; +import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; +import { BscStrategy } from '../impl/bsc.strategy'; +import { DeFiChainStrategy } from '../impl/defichain.strategy'; +import { EthereumStrategy } from '../impl/ethereum.strategy'; +import { PrepareStrategiesFacade, PrepareStrategyAlias } from '../prepare.facade'; + +describe('PrepareStrategiesFacade', () => { + let defichain: DeFiChainStrategy; + let ethereum: EthereumStrategy; + let bsc: BscStrategy; + + let facade: PrepareStrategiesFacadeWrapper; + + beforeEach(() => { + defichain = new DeFiChainStrategy( + mock(), + mock(), + mock(), + ); + ethereum = new EthereumStrategy(mock()); + bsc = new BscStrategy(mock()); + + facade = new PrepareStrategiesFacadeWrapper(defichain, ethereum, bsc); + }); + + describe('#constructor(...)', () => { + it('adds all prepareStrategies to a map', () => { + expect([...facade.getPrepareStrategies().entries()].length).toBe(3); + }); + + it('sets all required prepareStrategies aliases', () => { + const aliases = [...facade.getPrepareStrategies().keys()]; + + expect(aliases.includes(PrepareStrategyAlias.DEFICHAIN)).toBe(true); + expect(aliases.includes(PrepareStrategyAlias.ETHEREUM)).toBe(true); + expect(aliases.includes(PrepareStrategyAlias.BSC)).toBe(true); + }); + + it('assigns proper prepareStrategies to aliases', () => { + expect(facade.getPrepareStrategies().get(PrepareStrategyAlias.DEFICHAIN)).toBeInstanceOf(DeFiChainStrategy); + + expect(facade.getPrepareStrategies().get(PrepareStrategyAlias.ETHEREUM)).toBeInstanceOf(EthereumStrategy); + + expect(facade.getPrepareStrategies().get(PrepareStrategyAlias.BSC)).toBeInstanceOf(BscStrategy); + }); + }); + + describe('#getPrepareStrategy(...)', () => { + describe('getting strategy by Asset', () => { + it('gets ETHEREUM strategy', () => { + const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); + + expect(strategy).toBeInstanceOf(EthereumStrategy); + }); + + it('gets BSC strategy', () => { + const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN })); + + expect(strategy).toBeInstanceOf(BscStrategy); + }); + + it('gets DEFICHAIN strategy for DEFICHAIN', () => { + const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.DEFICHAIN })); + + expect(strategy).toBeInstanceOf(DeFiChainStrategy); + }); + + it('gets DEFICHAIN strategy for BITCOIN', () => { + const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.BITCOIN })); + + expect(strategy).toBeInstanceOf(DeFiChainStrategy); + }); + + it('fails to get strategy for non-supported Blockchain', () => { + const testCall = () => + facade.getPrepareStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No PrepareStrategy found. Alias: undefined'); + }); + }); + + describe('getting strategy by Alias', () => { + it('gets DEFICHAIN strategy', () => { + const strategy = facade.getPrepareStrategy(PrepareStrategyAlias.DEFICHAIN); + + expect(strategy).toBeInstanceOf(DeFiChainStrategy); + }); + + it('gets ETHEREUM strategy', () => { + const strategyCrypto = facade.getPrepareStrategy(PrepareStrategyAlias.ETHEREUM); + + expect(strategyCrypto).toBeInstanceOf(EthereumStrategy); + }); + + it('gets BSC strategy', () => { + const strategyCrypto = facade.getPrepareStrategy(PrepareStrategyAlias.BSC); + + expect(strategyCrypto).toBeInstanceOf(BscStrategy); + }); + + it('fails to get strategy for non-supported Alias', () => { + const testCall = () => facade.getPrepareStrategy('NonExistingAlias' as PrepareStrategyAlias); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No PrepareStrategy found. Alias: NonExistingAlias'); + }); + }); + }); +}); + +class PrepareStrategiesFacadeWrapper extends PrepareStrategiesFacade { + constructor(defichain: DeFiChainStrategy, ethereum: EthereumStrategy, bsc: BscStrategy) { + super(defichain, ethereum, bsc); + } + + getPrepareStrategies() { + return this.strategies; + } +} diff --git a/src/payment/models/payout/strategies/prepare/base/prepare-evm.strategy.ts b/src/payment/models/payout/strategies/prepare/impl/base/evm.strategy.ts similarity index 64% rename from src/payment/models/payout/strategies/prepare/base/prepare-evm.strategy.ts rename to src/payment/models/payout/strategies/prepare/impl/base/evm.strategy.ts index 143e71fb9d..6f2de01499 100644 --- a/src/payment/models/payout/strategies/prepare/base/prepare-evm.strategy.ts +++ b/src/payment/models/payout/strategies/prepare/impl/base/evm.strategy.ts @@ -1,8 +1,8 @@ -import { PayoutOrder } from '../../../entities/payout-order.entity'; -import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutOrder } from '../../../../entities/payout-order.entity'; +import { PayoutOrderRepository } from '../../../../repositories/payout-order.repository'; import { PrepareStrategy } from './prepare.strategy'; -export abstract class PrepareEvmStrategy implements PrepareStrategy { +export abstract class EvmStrategy implements PrepareStrategy { constructor(protected readonly payoutOrderRepo: PayoutOrderRepository) {} async preparePayout(order: PayoutOrder): Promise { diff --git a/src/payment/models/payout/strategies/prepare/base/prepare.strategy.ts b/src/payment/models/payout/strategies/prepare/impl/base/prepare.strategy.ts similarity index 68% rename from src/payment/models/payout/strategies/prepare/base/prepare.strategy.ts rename to src/payment/models/payout/strategies/prepare/impl/base/prepare.strategy.ts index 688ce60ae5..f3aba2e484 100644 --- a/src/payment/models/payout/strategies/prepare/base/prepare.strategy.ts +++ b/src/payment/models/payout/strategies/prepare/impl/base/prepare.strategy.ts @@ -1,4 +1,4 @@ -import { PayoutOrder } from '../../../entities/payout-order.entity'; +import { PayoutOrder } from '../../../../entities/payout-order.entity'; export interface PrepareStrategy { preparePayout(order: PayoutOrder): Promise; diff --git a/src/payment/models/payout/strategies/prepare/impl/bsc.strategy.ts b/src/payment/models/payout/strategies/prepare/impl/bsc.strategy.ts new file mode 100644 index 0000000000..7725b5996d --- /dev/null +++ b/src/payment/models/payout/strategies/prepare/impl/bsc.strategy.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { EvmStrategy } from './base/evm.strategy'; + +@Injectable() +export class BscStrategy extends EvmStrategy { + constructor(payoutOrderRepo: PayoutOrderRepository) { + super(payoutOrderRepo); + } +} diff --git a/src/payment/models/payout/strategies/prepare/prepare-defichain.strategy.ts b/src/payment/models/payout/strategies/prepare/impl/defichain.strategy.ts similarity index 85% rename from src/payment/models/payout/strategies/prepare/prepare-defichain.strategy.ts rename to src/payment/models/payout/strategies/prepare/impl/defichain.strategy.ts index 38741b19fc..2ca2bac7b4 100644 --- a/src/payment/models/payout/strategies/prepare/prepare-defichain.strategy.ts +++ b/src/payment/models/payout/strategies/prepare/impl/defichain.strategy.ts @@ -1,12 +1,12 @@ import { Injectable } from '@nestjs/common'; import { DexService } from 'src/payment/models/dex/services/dex.service'; -import { PayoutOrder } from '../../entities/payout-order.entity'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PayoutDeFiChainService } from '../../services/payout-defichain.service'; +import { PayoutOrder } from '../../../entities/payout-order.entity'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; import { PrepareStrategy } from './base/prepare.strategy'; @Injectable() -export class PrepareDeFiChainStrategy implements PrepareStrategy { +export class DeFiChainStrategy implements PrepareStrategy { constructor( private readonly dexService: DexService, private readonly defichainService: PayoutDeFiChainService, diff --git a/src/payment/models/payout/strategies/prepare/impl/ethereum.strategy.ts b/src/payment/models/payout/strategies/prepare/impl/ethereum.strategy.ts new file mode 100644 index 0000000000..e53acd59e1 --- /dev/null +++ b/src/payment/models/payout/strategies/prepare/impl/ethereum.strategy.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { EvmStrategy } from './base/evm.strategy'; + +@Injectable() +export class EthereumStrategy extends EvmStrategy { + constructor(payoutOrderRepo: PayoutOrderRepository) { + super(payoutOrderRepo); + } +} diff --git a/src/payment/models/payout/strategies/prepare/prepare-bsc.strategy.ts b/src/payment/models/payout/strategies/prepare/prepare-bsc.strategy.ts deleted file mode 100644 index df94ff5c22..0000000000 --- a/src/payment/models/payout/strategies/prepare/prepare-bsc.strategy.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PrepareEvmStrategy } from './base/prepare-evm.strategy'; - -@Injectable() -export class PrepareBscStrategy extends PrepareEvmStrategy { - constructor(payoutOrderRepo: PayoutOrderRepository) { - super(payoutOrderRepo); - } -} diff --git a/src/payment/models/payout/strategies/prepare/prepare-ethereum.strategy.ts b/src/payment/models/payout/strategies/prepare/prepare-ethereum.strategy.ts deleted file mode 100644 index 7ebca7123e..0000000000 --- a/src/payment/models/payout/strategies/prepare/prepare-ethereum.strategy.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PrepareEvmStrategy } from './base/prepare-evm.strategy'; - -@Injectable() -export class PrepareEthereumStrategy extends PrepareEvmStrategy { - constructor(payoutOrderRepo: PayoutOrderRepository) { - super(payoutOrderRepo); - } -} diff --git a/src/payment/models/payout/strategies/prepare/prepare.facade.ts b/src/payment/models/payout/strategies/prepare/prepare.facade.ts new file mode 100644 index 0000000000..3b5eb5a6b3 --- /dev/null +++ b/src/payment/models/payout/strategies/prepare/prepare.facade.ts @@ -0,0 +1,54 @@ +import { Injectable } from '@nestjs/common'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { Asset } from 'src/shared/models/asset/asset.entity'; +import { PrepareStrategy } from './impl/base/prepare.strategy'; +import { BscStrategy } from './impl/bsc.strategy'; +import { DeFiChainStrategy } from './impl/defichain.strategy'; +import { EthereumStrategy } from './impl/ethereum.strategy'; + +enum Alias { + DEFICHAIN = 'DeFiChain', + ETHEREUM = 'Ethereum', + BSC = 'Bsc', +} + +export { Alias as PrepareStrategyAlias }; + +@Injectable() +export class PrepareStrategiesFacade { + protected readonly strategies: Map = new Map(); + + constructor(deFiChainStrategy: DeFiChainStrategy, ethereumStrategy: EthereumStrategy, bscStrategy: BscStrategy) { + this.strategies.set(Alias.DEFICHAIN, deFiChainStrategy); + this.strategies.set(Alias.ETHEREUM, ethereumStrategy); + this.strategies.set(Alias.BSC, bscStrategy); + } + + getPrepareStrategy(criteria: Asset | Alias): PrepareStrategy { + return criteria instanceof Asset ? this.getByAsset(criteria) : this.getByAlias(criteria); + } + + //*** HELPER METHODS ***// + + private getByAlias(alias: Alias): PrepareStrategy { + const strategy = this.strategies.get(alias); + + if (!strategy) throw new Error(`No PrepareStrategy found. Alias: ${alias}`); + + return strategy; + } + + private getByAsset(asset: Asset): PrepareStrategy { + const alias = this.getAlias(asset); + + return this.getByAlias(alias); + } + + private getAlias(asset: Asset): Alias { + const { blockchain } = asset; + + if (blockchain === Blockchain.ETHEREUM) return Alias.ETHEREUM; + if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return Alias.BSC; + if (blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) return Alias.DEFICHAIN; + } +} diff --git a/src/payment/models/payout/strategies/strategies.facade.ts b/src/payment/models/payout/strategies/strategies.facade.ts deleted file mode 100644 index 71ce7ef349..0000000000 --- a/src/payment/models/payout/strategies/strategies.facade.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { Asset } from 'src/shared/models/asset/asset.entity'; -import { PayoutBscCryptoStrategy } from './payout/payout-bsc-crypto.strategy'; -import { PayoutDeFiChainDFIStrategy } from './payout/payout-defichain-dfi.strategy'; -import { PayoutEthereumCryptoStrategy } from './payout/payout-ethereum-crypto.strategy'; -import { PayoutDeFiChainTokenStrategy } from './payout/payout-defichain-token.strategy'; -import { PayoutStrategy } from './payout/base/payout.strategy'; -import { PrepareBscStrategy } from './prepare/prepare-bsc.strategy'; -import { PrepareDeFiChainStrategy } from './prepare/prepare-defichain.strategy'; -import { PrepareEthereumStrategy } from './prepare/prepare-ethereum.strategy'; -import { PrepareStrategy } from './prepare/base/prepare.strategy'; - -export enum PayoutStrategyAlias { - DEFICHAIN_DFI = 'DeFiChainDFI', - DEFICHAIN_TOKEN = 'DeFiChainToken', - ETHEREUM_DEFAULT = 'Ethereum', - BSC_DEFAULT = 'BscDefault', -} - -export enum PrepareStrategyAlias { - DEFICHAIN = 'DeFiChain', - ETHEREUM = 'Ethereum', - BSC = 'Bsc', -} - -@Injectable() -export class PayoutStrategiesFacade { - protected readonly payoutStrategies: Map = new Map(); - protected readonly prepareStrategies: Map = new Map(); - - constructor( - payoutDFIStrategy: PayoutDeFiChainDFIStrategy, - payoutTokenStrategy: PayoutDeFiChainTokenStrategy, - payoutEthStrategy: PayoutEthereumCryptoStrategy, - payoutBscStrategy: PayoutBscCryptoStrategy, - prepareOnDefichainStrategy: PrepareDeFiChainStrategy, - prepareOnEthereumStrategy: PrepareEthereumStrategy, - prepareOnBscStrategy: PrepareBscStrategy, - ) { - this.payoutStrategies.set(PayoutStrategyAlias.DEFICHAIN_DFI, payoutDFIStrategy); - this.payoutStrategies.set(PayoutStrategyAlias.DEFICHAIN_TOKEN, payoutTokenStrategy); - this.payoutStrategies.set(PayoutStrategyAlias.ETHEREUM_DEFAULT, payoutEthStrategy); - this.payoutStrategies.set(PayoutStrategyAlias.BSC_DEFAULT, payoutBscStrategy); - - this.prepareStrategies.set(PrepareStrategyAlias.DEFICHAIN, prepareOnDefichainStrategy); - this.prepareStrategies.set(PrepareStrategyAlias.ETHEREUM, prepareOnEthereumStrategy); - this.prepareStrategies.set(PrepareStrategyAlias.BSC, prepareOnBscStrategy); - } - - getPayoutStrategy(criteria: Asset | PayoutStrategyAlias): PayoutStrategy { - return criteria instanceof Asset - ? this.getPayoutStrategyByAsset(criteria) - : this.getPayoutStrategyByAlias(criteria); - } - - getPrepareStrategy(criteria: Asset | PrepareStrategyAlias): PrepareStrategy { - return criteria instanceof Asset - ? this.getPrepareStrategyByAsset(criteria) - : this.getPrepareStrategyByAlias(criteria); - } - - //*** HELPER METHODS ***// - - private getPayoutStrategyByAlias(alias: PayoutStrategyAlias): PayoutStrategy { - const strategy = this.payoutStrategies.get(alias); - - if (!strategy) throw new Error(`No PayoutStrategy found. Alias: ${alias}`); - - return strategy; - } - - private getPayoutStrategyByAsset(asset: Asset): PayoutStrategy { - const alias = this.getPayoutStrategyAlias(asset); - - return this.getPayoutStrategyByAlias(alias); - } - - private getPrepareStrategyByAlias(alias: PrepareStrategyAlias): PrepareStrategy { - const strategy = this.prepareStrategies.get(alias); - - if (!strategy) throw new Error(`No PrepareStrategy found. Alias: ${alias}`); - - return strategy; - } - - private getPrepareStrategyByAsset(asset: Asset): PrepareStrategy { - const alias = this.getPrepareStrategyAlias(asset); - - return this.getPrepareStrategyByAlias(alias); - } - - private getPayoutStrategyAlias(asset: Asset): PayoutStrategyAlias { - const { blockchain, dexName: assetName } = asset; - - if (blockchain === Blockchain.ETHEREUM) return PayoutStrategyAlias.ETHEREUM_DEFAULT; - if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return PayoutStrategyAlias.BSC_DEFAULT; - if (blockchain === Blockchain.DEFICHAIN && assetName === 'DFI') return PayoutStrategyAlias.DEFICHAIN_DFI; - if ((blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) && assetName !== 'DFI') { - return PayoutStrategyAlias.DEFICHAIN_TOKEN; - } - } - - private getPrepareStrategyAlias(asset: Asset): PrepareStrategyAlias { - const { blockchain } = asset; - - if (blockchain === Blockchain.ETHEREUM) return PrepareStrategyAlias.ETHEREUM; - if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return PrepareStrategyAlias.BSC; - if (blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) return PrepareStrategyAlias.DEFICHAIN; - } -} From e11bbb08acf5c481ba9eeb1e21bfb55937c55dfa Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 3 Oct 2022 13:35:53 +0200 Subject: [PATCH 06/30] [DEV-622] added payout strategies placeholders --- .../models/payout/services/payout.service.ts | 4 +- .../__tests__/payout.facade.spec.ts | 170 ------------- .../payout/__tests__/payout.facade.spec.ts | 227 ++++++++++++++++++ .../payout/strategies/payout/payout.facade.ts | 49 +++- .../prepare/__tests__/prepare.facade.spec.ts | 12 +- 5 files changed, 272 insertions(+), 190 deletions(-) delete mode 100644 src/payment/models/payout/strategies/__tests__/payout.facade.spec.ts create mode 100644 src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts diff --git a/src/payment/models/payout/services/payout.service.ts b/src/payment/models/payout/services/payout.service.ts index 76d9286592..1a8a4fe05a 100644 --- a/src/payment/models/payout/services/payout.service.ts +++ b/src/payment/models/payout/services/payout.service.ts @@ -150,8 +150,8 @@ export class PayoutService { const dfiStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_DFI); const tokenStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_TOKEN); - const ethStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_DEFAULT); - const bnbStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.BSC_DEFAULT); + const ethStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_CRYPTO); + const bnbStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.BSC_CRYPTO); await dfiStrategy.doPayout(dfiOrders); await tokenStrategy.doPayout(tokenOrders); diff --git a/src/payment/models/payout/strategies/__tests__/payout.facade.spec.ts b/src/payment/models/payout/strategies/__tests__/payout.facade.spec.ts deleted file mode 100644 index cc114b4260..0000000000 --- a/src/payment/models/payout/strategies/__tests__/payout.facade.spec.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { mock } from 'jest-mock-extended'; -import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { DexService } from 'src/payment/models/dex/services/dex.service'; -import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; -import { MailService } from 'src/shared/services/mail.service'; -import { PayoutOrderRepository } from '../../repositories/payout-order.repository'; -import { PayoutBscService } from '../../services/payout-bsc.service'; -import { PayoutDeFiChainService } from '../../services/payout-defichain.service'; -import { PayoutEthereumService } from '../../services/payout-ethereum.service'; -import { BscCryptoStrategy } from '../payout/impl/bsc-crypto.strategy'; -import { DeFiChainDfiStrategy } from '../payout/impl/defichain-dfi.strategy'; -import { DeFiChainTokenStrategy } from '../payout/impl/defichain-token.strategy'; -import { EthereumCryptoStrategy } from '../payout/impl/ethereum-crypto.strategy'; -import { PayoutStrategiesFacade, PayoutStrategyAlias } from '../payout/payout.facade'; - -describe('PayoutStrategiesFacade', () => { - let dfi: DeFiChainDfiStrategy; - let token: DeFiChainTokenStrategy; - let ethCrypto: EthereumCryptoStrategy; - let bscCrypto: BscCryptoStrategy; - - let facade: PayoutStrategiesFacadeWrapper; - - beforeEach(() => { - dfi = new DeFiChainDfiStrategy(mock(), mock(), mock()); - token = new DeFiChainTokenStrategy( - mock(), - mock(), - mock(), - mock(), - ); - ethCrypto = new EthereumCryptoStrategy(mock(), mock()); - bscCrypto = new BscCryptoStrategy(mock(), mock()); - - facade = new PayoutStrategiesFacadeWrapper(dfi, token, ethCrypto, bscCrypto); - }); - - describe('#constructor(...)', () => { - it('adds all payoutStrategies to a map', () => { - expect([...facade.getPayoutStrategies().entries()].length).toBe(4); - }); - - it('sets all required payoutStrategies aliases', () => { - const aliases = [...facade.getPayoutStrategies().keys()]; - - expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_DFI)).toBe(true); - expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_TOKEN)).toBe(true); - expect(aliases.includes(PayoutStrategyAlias.ETHEREUM_DEFAULT)).toBe(true); - expect(aliases.includes(PayoutStrategyAlias.BSC_DEFAULT)).toBe(true); - }); - - it('assigns proper payoutStrategies to aliases', () => { - expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.DEFICHAIN_DFI)).toBeInstanceOf(DeFiChainDfiStrategy); - - expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.DEFICHAIN_TOKEN)).toBeInstanceOf( - DeFiChainTokenStrategy, - ); - - expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.ETHEREUM_DEFAULT)).toBeInstanceOf( - EthereumCryptoStrategy, - ); - - expect(facade.getPayoutStrategies().get(PayoutStrategyAlias.BSC_DEFAULT)).toBeInstanceOf(BscCryptoStrategy); - }); - }); - - describe('#getPayoutStrategy(...)', () => { - describe('getting strategy by Asset', () => { - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); - - expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); - }); - - it('gets BSC_DEFAULT strategy', () => { - const strategy = facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN })); - - expect(strategy).toBeInstanceOf(BscCryptoStrategy); - }); - - it('gets DEFICHAIN_DFI strategy', () => { - const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, dexName: 'DFI' }), - ); - - expect(strategy).toBeInstanceOf(DeFiChainDfiStrategy); - }); - - it('gets DEFICHAIN_TOKEN strategy for DEFICHAIN', () => { - const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, dexName: 'non-DFI' }), - ); - - expect(strategy).toBeInstanceOf(DeFiChainTokenStrategy); - }); - - it('gets DEFICHAIN_TOKEN strategy for BITCOIN', () => { - const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.BITCOIN, dexName: 'non-DFI' }), - ); - - expect(strategy).toBeInstanceOf(DeFiChainTokenStrategy); - }); - - it('fails to get strategy for non-supported Blockchain', () => { - const testCall = () => - facade.getPayoutStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PayoutStrategy found. Alias: undefined'); - }); - - it('fails to get strategy for DFI on Bitcoin blockchain', () => { - const testCall = () => - facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.BITCOIN, dexName: 'DFI' })); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PayoutStrategy found. Alias: undefined'); - }); - }); - - describe('getting strategy by Alias', () => { - it('gets ETHEREUM_DEFAULT strategy', () => { - const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_DEFAULT); - - expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); - }); - - it('gets BSC_DEFAULT strategy', () => { - const strategyCrypto = facade.getPayoutStrategy(PayoutStrategyAlias.BSC_DEFAULT); - - expect(strategyCrypto).toBeInstanceOf(BscCryptoStrategy); - }); - - it('gets DEFICHAIN_DFI strategy', () => { - const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_DFI); - - expect(strategy).toBeInstanceOf(DeFiChainDfiStrategy); - }); - - it('gets DEFICHAIN_TOKEN strategy', () => { - const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_TOKEN); - - expect(strategy).toBeInstanceOf(DeFiChainTokenStrategy); - }); - - it('fails to get strategy for non-supported Alias', () => { - const testCall = () => facade.getPayoutStrategy('NonExistingAlias' as PayoutStrategyAlias); - - expect(testCall).toThrow(); - expect(testCall).toThrowError('No PayoutStrategy found. Alias: NonExistingAlias'); - }); - }); - }); -}); - -class PayoutStrategiesFacadeWrapper extends PayoutStrategiesFacade { - constructor( - payoutDFIStrategy: DeFiChainDfiStrategy, - payoutTokenStrategy: DeFiChainTokenStrategy, - payoutETHStrategy: EthereumCryptoStrategy, - payoutBSCStrategy: BscCryptoStrategy, - ) { - super(payoutDFIStrategy, payoutTokenStrategy, payoutETHStrategy, payoutBSCStrategy); - } - - getPayoutStrategies() { - return this.strategies; - } -} diff --git a/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts b/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts new file mode 100644 index 0000000000..4820e80210 --- /dev/null +++ b/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts @@ -0,0 +1,227 @@ +import { mock } from 'jest-mock-extended'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { DexService } from 'src/payment/models/dex/services/dex.service'; +import { AssetCategory } from 'src/shared/models/asset/asset.entity'; +import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; +import { MailService } from 'src/shared/services/mail.service'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutBitcoinService } from '../../../services/payout-bitcoin.service'; +import { PayoutBscService } from '../../../services/payout-bsc.service'; +import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; +import { PayoutEthereumService } from '../../../services/payout-ethereum.service'; +import { BitcoinStrategy } from '../impl/bitcoin.strategy'; +import { BscCryptoStrategy } from '../impl/bsc-crypto.strategy'; +import { BscTokenStrategy } from '../impl/bsc-token.strategy'; +import { DeFiChainDfiStrategy } from '../impl/defichain-dfi.strategy'; +import { DeFiChainTokenStrategy } from '../impl/defichain-token.strategy'; +import { EthereumCryptoStrategy } from '../impl/ethereum-crypto.strategy'; +import { EthereumTokenStrategy } from '../impl/ethereum-token.strategy'; +import { PayoutStrategiesFacade, PayoutStrategyAlias } from '../payout.facade'; + +describe('PayoutStrategiesFacade', () => { + let bitcoin: BitcoinStrategy; + let deFiChainDfi: DeFiChainDfiStrategy; + let deFiChainToken: DeFiChainTokenStrategy; + let ethereumCrypto: EthereumCryptoStrategy; + let ethereumToken: EthereumTokenStrategy; + let bscCrypto: BscCryptoStrategy; + let bscToken: BscTokenStrategy; + + let facade: PayoutStrategiesFacadeWrapper; + + beforeEach(() => { + bitcoin = new BitcoinStrategy(mock(), mock()); + deFiChainDfi = new DeFiChainDfiStrategy( + mock(), + mock(), + mock(), + ); + deFiChainToken = new DeFiChainTokenStrategy( + mock(), + mock(), + mock(), + mock(), + ); + ethereumCrypto = new EthereumCryptoStrategy(mock(), mock()); + ethereumToken = new EthereumTokenStrategy(mock(), mock()); + bscCrypto = new BscCryptoStrategy(mock(), mock()); + bscToken = new BscTokenStrategy(mock(), mock()); + + facade = new PayoutStrategiesFacadeWrapper( + bitcoin, + bscCrypto, + bscToken, + deFiChainDfi, + deFiChainToken, + ethereumCrypto, + ethereumToken, + ); + }); + + describe('#constructor(...)', () => { + it('adds all payoutStrategies to a map', () => { + expect([...facade.getStrategies().entries()].length).toBe(7); + }); + + it('assigns strategies to all aliases', () => { + expect([...facade.getStrategies().entries()].length).toBe(Object.values(PayoutStrategyAlias).length); + }); + + it('sets all required payoutStrategies aliases', () => { + const aliases = [...facade.getStrategies().keys()]; + + expect(aliases.includes(PayoutStrategyAlias.BITCOIN)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.BSC_TOKEN)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.BSC_CRYPTO)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_DFI)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_TOKEN)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.ETHEREUM_CRYPTO)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.ETHEREUM_TOKEN)).toBe(true); + }); + + it('assigns proper payoutStrategies to aliases', () => { + expect(facade.getStrategies().get(PayoutStrategyAlias.BITCOIN)).toBeInstanceOf(BitcoinStrategy); + expect(facade.getStrategies().get(PayoutStrategyAlias.BSC_CRYPTO)).toBeInstanceOf(BscCryptoStrategy); + expect(facade.getStrategies().get(PayoutStrategyAlias.BSC_TOKEN)).toBeInstanceOf(BscTokenStrategy); + expect(facade.getStrategies().get(PayoutStrategyAlias.DEFICHAIN_DFI)).toBeInstanceOf(DeFiChainDfiStrategy); + expect(facade.getStrategies().get(PayoutStrategyAlias.DEFICHAIN_TOKEN)).toBeInstanceOf(DeFiChainTokenStrategy); + expect(facade.getStrategies().get(PayoutStrategyAlias.ETHEREUM_CRYPTO)).toBeInstanceOf(EthereumCryptoStrategy); + expect(facade.getStrategies().get(PayoutStrategyAlias.ETHEREUM_TOKEN)).toBeInstanceOf(EthereumTokenStrategy); + }); + }); + + describe('#getPayoutStrategy(...)', () => { + describe('getting strategy by Asset', () => { + it('gets BITCOIN strategy for BITCOIN', () => { + const strategy = facade.getPayoutStrategy(createCustomAsset({ blockchain: Blockchain.BITCOIN })); + + expect(strategy).toBeInstanceOf(BitcoinStrategy); + }); + + it('gets BSC_CRYPTO strategy', () => { + const strategy = facade.getPayoutStrategy( + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.CRYPTO }), + ); + + expect(strategy).toBeInstanceOf(BscCryptoStrategy); + }); + + it('gets BSC_TOKEN strategy', () => { + const strategy = facade.getPayoutStrategy( + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.STOCK }), + ); + + expect(strategy).toBeInstanceOf(BscTokenStrategy); + }); + + it('gets DEFICHAIN_DFI strategy', () => { + const strategy = facade.getPayoutStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, dexName: 'DFI' }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainDfiStrategy); + }); + + it('gets DEFICHAIN_TOKEN strategy for DEFICHAIN', () => { + const strategy = facade.getPayoutStrategy( + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, dexName: 'non-DFI' }), + ); + + expect(strategy).toBeInstanceOf(DeFiChainTokenStrategy); + }); + + it('gets ETHEREUM_CRYPTO strategy', () => { + const strategy = facade.getPayoutStrategy( + createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.CRYPTO }), + ); + + expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + }); + + it('gets ETHEREUM_TOKEN strategy', () => { + const strategy = facade.getPayoutStrategy( + createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.STOCK }), + ); + + expect(strategy).toBeInstanceOf(EthereumTokenStrategy); + }); + + it('fails to get strategy for non-supported Blockchain', () => { + const testCall = () => + facade.getPayoutStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No PayoutStrategy found. Alias: undefined'); + }); + }); + + describe('getting strategy by Alias', () => { + it('gets BITCOIN strategy', () => { + const strategyCrypto = facade.getPayoutStrategy(PayoutStrategyAlias.BITCOIN); + + expect(strategyCrypto).toBeInstanceOf(BitcoinStrategy); + }); + + it('gets BSC_CRYPTO strategy', () => { + const strategyCrypto = facade.getPayoutStrategy(PayoutStrategyAlias.BSC_CRYPTO); + + expect(strategyCrypto).toBeInstanceOf(BscCryptoStrategy); + }); + + it('gets BSC_TOKEN strategy', () => { + const strategyCrypto = facade.getPayoutStrategy(PayoutStrategyAlias.BSC_TOKEN); + + expect(strategyCrypto).toBeInstanceOf(BscTokenStrategy); + }); + + it('gets DEFICHAIN_DFI strategy', () => { + const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_DFI); + + expect(strategy).toBeInstanceOf(DeFiChainDfiStrategy); + }); + + it('gets DEFICHAIN_TOKEN strategy', () => { + const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_TOKEN); + + expect(strategy).toBeInstanceOf(DeFiChainTokenStrategy); + }); + + it('gets ETHEREUM_CRYPTO strategy', () => { + const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_CRYPTO); + + expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + }); + + it('gets ETHEREUM_TOKEN strategy', () => { + const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_TOKEN); + + expect(strategy).toBeInstanceOf(EthereumTokenStrategy); + }); + + it('fails to get strategy for non-supported Alias', () => { + const testCall = () => facade.getPayoutStrategy('NonExistingAlias' as PayoutStrategyAlias); + + expect(testCall).toThrow(); + expect(testCall).toThrowError('No PayoutStrategy found. Alias: NonExistingAlias'); + }); + }); + }); +}); + +class PayoutStrategiesFacadeWrapper extends PayoutStrategiesFacade { + constructor( + bitcoin: BitcoinStrategy, + bscCrypto: BscCryptoStrategy, + bscToken: BscTokenStrategy, + deFiChainDfi: DeFiChainDfiStrategy, + deFiChainToken: DeFiChainTokenStrategy, + ethereumCrypto: EthereumCryptoStrategy, + ethereumToken: EthereumTokenStrategy, + ) { + super(bitcoin, bscCrypto, bscToken, deFiChainDfi, deFiChainToken, ethereumCrypto, ethereumToken); + } + + getStrategies() { + return this.strategies; + } +} diff --git a/src/payment/models/payout/strategies/payout/payout.facade.ts b/src/payment/models/payout/strategies/payout/payout.facade.ts index 9fc1167983..56b0a5616b 100644 --- a/src/payment/models/payout/strategies/payout/payout.facade.ts +++ b/src/payment/models/payout/strategies/payout/payout.facade.ts @@ -1,17 +1,23 @@ import { Injectable } from '@nestjs/common'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { Asset } from 'src/shared/models/asset/asset.entity'; +import { Asset, AssetCategory } from 'src/shared/models/asset/asset.entity'; import { PayoutStrategy } from './impl/base/payout.strategy'; +import { BitcoinStrategy } from './impl/bitcoin.strategy'; import { BscCryptoStrategy } from './impl/bsc-crypto.strategy'; +import { BscTokenStrategy } from './impl/bsc-token.strategy'; import { DeFiChainDfiStrategy } from './impl/defichain-dfi.strategy'; import { DeFiChainTokenStrategy } from './impl/defichain-token.strategy'; import { EthereumCryptoStrategy } from './impl/ethereum-crypto.strategy'; +import { EthereumTokenStrategy } from './impl/ethereum-token.strategy'; enum Alias { + BITCOIN = 'Bitcoin', + BSC_CRYPTO = 'BscCrypto', + BSC_TOKEN = 'BscToken', DEFICHAIN_DFI = 'DeFiChainDFI', DEFICHAIN_TOKEN = 'DeFiChainToken', - ETHEREUM_DEFAULT = 'Ethereum', - BSC_DEFAULT = 'BscDefault', + ETHEREUM_CRYPTO = 'EthereumCrypto', + ETHEREUM_TOKEN = 'EthereumToken', } export { Alias as PayoutStrategyAlias }; @@ -21,15 +27,21 @@ export class PayoutStrategiesFacade { protected readonly strategies: Map = new Map(); constructor( + bitcoin: BitcoinStrategy, + bscCrypto: BscCryptoStrategy, + bscToken: BscTokenStrategy, deFiChainDfi: DeFiChainDfiStrategy, deFiChainToken: DeFiChainTokenStrategy, ethereumCrypto: EthereumCryptoStrategy, - bscCrypto: BscCryptoStrategy, + ethereumToken: EthereumTokenStrategy, ) { + this.strategies.set(Alias.BITCOIN, bitcoin); + this.strategies.set(Alias.BSC_CRYPTO, bscCrypto); + this.strategies.set(Alias.BSC_TOKEN, bscToken); this.strategies.set(Alias.DEFICHAIN_DFI, deFiChainDfi); this.strategies.set(Alias.DEFICHAIN_TOKEN, deFiChainToken); - this.strategies.set(Alias.ETHEREUM_DEFAULT, ethereumCrypto); - this.strategies.set(Alias.BSC_DEFAULT, bscCrypto); + this.strategies.set(Alias.ETHEREUM_CRYPTO, ethereumCrypto); + this.strategies.set(Alias.ETHEREUM_TOKEN, ethereumToken); } getPayoutStrategy(criteria: Asset | Alias): PayoutStrategy { @@ -53,13 +65,26 @@ export class PayoutStrategiesFacade { } private getAlias(asset: Asset): Alias { - const { blockchain, dexName: assetName } = asset; + const { blockchain, dexName: assetName, category: assetCategory } = asset; + + if (blockchain === Blockchain.BITCOIN) return Alias.BITCOIN; + + if (blockchain === Blockchain.BINANCE_SMART_CHAIN) { + if (assetCategory === AssetCategory.CRYPTO) return Alias.BSC_CRYPTO; + if (assetCategory === AssetCategory.STOCK) return Alias.BSC_TOKEN; + } + + if (blockchain === Blockchain.DEFICHAIN) { + if (assetName === 'DFI') { + return Alias.DEFICHAIN_DFI; + } else { + return Alias.DEFICHAIN_TOKEN; + } + } - if (blockchain === Blockchain.ETHEREUM) return Alias.ETHEREUM_DEFAULT; - if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return Alias.BSC_DEFAULT; - if (blockchain === Blockchain.DEFICHAIN && assetName === 'DFI') return Alias.DEFICHAIN_DFI; - if ((blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) && assetName !== 'DFI') { - return Alias.DEFICHAIN_TOKEN; + if (blockchain === Blockchain.ETHEREUM) { + if (assetCategory === AssetCategory.CRYPTO) return Alias.ETHEREUM_CRYPTO; + if (assetCategory === AssetCategory.STOCK) return Alias.ETHEREUM_TOKEN; } } } diff --git a/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts b/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts index 4b257f9568..7563b6a7e1 100644 --- a/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts +++ b/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts @@ -30,11 +30,11 @@ describe('PrepareStrategiesFacade', () => { describe('#constructor(...)', () => { it('adds all prepareStrategies to a map', () => { - expect([...facade.getPrepareStrategies().entries()].length).toBe(3); + expect([...facade.getStrategies().entries()].length).toBe(3); }); it('sets all required prepareStrategies aliases', () => { - const aliases = [...facade.getPrepareStrategies().keys()]; + const aliases = [...facade.getStrategies().keys()]; expect(aliases.includes(PrepareStrategyAlias.DEFICHAIN)).toBe(true); expect(aliases.includes(PrepareStrategyAlias.ETHEREUM)).toBe(true); @@ -42,11 +42,11 @@ describe('PrepareStrategiesFacade', () => { }); it('assigns proper prepareStrategies to aliases', () => { - expect(facade.getPrepareStrategies().get(PrepareStrategyAlias.DEFICHAIN)).toBeInstanceOf(DeFiChainStrategy); + expect(facade.getStrategies().get(PrepareStrategyAlias.DEFICHAIN)).toBeInstanceOf(DeFiChainStrategy); - expect(facade.getPrepareStrategies().get(PrepareStrategyAlias.ETHEREUM)).toBeInstanceOf(EthereumStrategy); + expect(facade.getStrategies().get(PrepareStrategyAlias.ETHEREUM)).toBeInstanceOf(EthereumStrategy); - expect(facade.getPrepareStrategies().get(PrepareStrategyAlias.BSC)).toBeInstanceOf(BscStrategy); + expect(facade.getStrategies().get(PrepareStrategyAlias.BSC)).toBeInstanceOf(BscStrategy); }); }); @@ -119,7 +119,7 @@ class PrepareStrategiesFacadeWrapper extends PrepareStrategiesFacade { super(defichain, ethereum, bsc); } - getPrepareStrategies() { + getStrategies() { return this.strategies; } } From f5e64c3ce535c5589846f6c23686d01a0f04ef5f Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 3 Oct 2022 13:39:58 +0200 Subject: [PATCH 07/30] [DEV-622] private methds naming cleanup in dex module --- .../check-liquidity/check-liquidity.facade.ts | 10 ++++------ .../purchase-liquidity/purchase-liquidity.facade.ts | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts index 179c92e894..9589548483 100644 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts +++ b/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts @@ -45,14 +45,12 @@ export class CheckLiquidityStrategies { } getCheckLiquidityStrategy(criteria: Asset | Alias): CheckLiquidityStrategy { - return criteria instanceof Asset - ? this.getCheckLiquidityStrategyByAsset(criteria) - : this.getCheckLiquidityStrategyByAlias(criteria); + return criteria instanceof Asset ? this.getByAsset(criteria) : this.getByAlias(criteria); } //*** HELPER METHODS ***// - private getCheckLiquidityStrategyByAlias(alias: Alias): CheckLiquidityStrategy { + private getByAlias(alias: Alias): CheckLiquidityStrategy { const strategy = this.strategies.get(alias); if (!strategy) throw new Error(`No CheckLiquidityStrategy found. Alias: ${alias}`); @@ -60,10 +58,10 @@ export class CheckLiquidityStrategies { return strategy; } - private getCheckLiquidityStrategyByAsset(asset: Asset): CheckLiquidityStrategy { + private getByAsset(asset: Asset): CheckLiquidityStrategy { const alias = this.getAlias(asset); - return this.getCheckLiquidityStrategyByAlias(alias); + return this.getByAlias(alias); } private getAlias(asset: Asset): Alias { diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts index 48eddc7dd0..fcdebfb2bc 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts @@ -50,14 +50,12 @@ export class PurchaseLiquidityStrategies { } getPurchaseLiquidityStrategy(criteria: Asset | Alias): PurchaseLiquidityStrategy { - return criteria instanceof Asset - ? this.getPurchaseLiquidityStrategyByAsset(criteria) - : this.getPurchaseLiquidityStrategyByAlias(criteria); + return criteria instanceof Asset ? this.getByAsset(criteria) : this.getByAlias(criteria); } //*** HELPER METHODS ***// - private getPurchaseLiquidityStrategyByAlias(alias: Alias): PurchaseLiquidityStrategy { + private getByAlias(alias: Alias): PurchaseLiquidityStrategy { const strategy = this.strategies.get(alias); if (!strategy) throw new Error(`No PurchaseLiquidityStrategy found. Alias: ${alias}`); @@ -65,10 +63,10 @@ export class PurchaseLiquidityStrategies { return strategy; } - private getPurchaseLiquidityStrategyByAsset(asset: Asset): PurchaseLiquidityStrategy { + private getByAsset(asset: Asset): PurchaseLiquidityStrategy { const alias = this.getAlias(asset); - return this.getPurchaseLiquidityStrategyByAlias(alias); + return this.getByAlias(alias); } private getAlias(asset: Asset): Alias { From 57a3ef9087154d69d267364e2f1d5e8d0b81dfd3 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 3 Oct 2022 14:32:11 +0200 Subject: [PATCH 08/30] [DEV-622] refactored payout service to group orders by strategies --- .../models/payout/services/payout.service.ts | 48 ++++++++++++------- .../payout/strategies/payout/payout.facade.ts | 34 ++++++------- 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/src/payment/models/payout/services/payout.service.ts b/src/payment/models/payout/services/payout.service.ts index 1a8a4fe05a..619b11f5aa 100644 --- a/src/payment/models/payout/services/payout.service.ts +++ b/src/payment/models/payout/services/payout.service.ts @@ -1,13 +1,12 @@ import { Injectable } from '@nestjs/common'; import { Interval } from '@nestjs/schedule'; import { Lock } from 'src/shared/lock'; -import { PayoutOrderContext, PayoutOrderStatus } from '../entities/payout-order.entity'; +import { PayoutOrder, PayoutOrderContext, PayoutOrderStatus } from '../entities/payout-order.entity'; import { PayoutOrderFactory } from '../factories/payout-order.factory'; import { PayoutOrderRepository } from '../repositories/payout-order.repository'; import { DuplicatedEntryException } from '../exceptions/duplicated-entry.exception'; import { MailService } from 'src/shared/services/mail.service'; import { PayoutStrategiesFacade, PayoutStrategyAlias } from '../strategies/payout/payout.facade'; -import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; import { PayoutLogService } from './payout-log.service'; import { PayoutRequest } from '../interfaces'; import { PrepareStrategiesFacade } from '../strategies/prepare/prepare.facade'; @@ -140,23 +139,16 @@ export class PayoutService { private async payoutOrders(): Promise { const orders = await this.payoutOrderRepo.find({ status: PayoutOrderStatus.PREPARATION_CONFIRMED }); + const groups = this.groupOrdersByPayoutStrategies(orders); - const dfiOrders = orders.filter((o) => o.asset.blockchain === Blockchain.DEFICHAIN && o.asset.dexName === 'DFI'); - const tokenOrders = orders.filter((o) => o.asset.blockchain === Blockchain.DEFICHAIN && o.asset.dexName !== 'DFI'); - const ethOrders = orders.filter((o) => o.asset.blockchain === Blockchain.ETHEREUM && o.asset.dexName === 'ETH'); - const bnbOrders = orders.filter( - (o) => o.asset.blockchain === Blockchain.BINANCE_SMART_CHAIN && o.asset.dexName === 'BNB', - ); - - const dfiStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_DFI); - const tokenStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_TOKEN); - const ethStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_CRYPTO); - const bnbStrategy = this.payoutStrategies.getPayoutStrategy(PayoutStrategyAlias.BSC_CRYPTO); - - await dfiStrategy.doPayout(dfiOrders); - await tokenStrategy.doPayout(tokenOrders); - await ethStrategy.doPayout(ethOrders); - await bnbStrategy.doPayout(bnbOrders); + for (const group of groups.entries()) { + try { + const strategy = this.payoutStrategies.getPayoutStrategy(group[0]); + await strategy.doPayout(group[1]); + } catch { + continue; + } + } } private async processFailedOrders(): Promise { @@ -172,4 +164,24 @@ export class PayoutService { await this.payoutOrderRepo.save(order); } } + + private groupOrdersByPayoutStrategies(orders: PayoutOrder[]): Map { + const groups = new Map(); + + for (const order of orders) { + const alias = this.payoutStrategies.getPayoutStrategyAlias(order.asset); + + if (!alias) { + console.warn(`No payout alias found for payout order ID ${order.id}. Ignoring the order`); + continue; + } + + const group = groups.get(alias) ?? []; + group.push(order); + + groups.set(alias, group); + } + + return groups; + } } diff --git a/src/payment/models/payout/strategies/payout/payout.facade.ts b/src/payment/models/payout/strategies/payout/payout.facade.ts index 56b0a5616b..738dc437be 100644 --- a/src/payment/models/payout/strategies/payout/payout.facade.ts +++ b/src/payment/models/payout/strategies/payout/payout.facade.ts @@ -48,23 +48,7 @@ export class PayoutStrategiesFacade { return criteria instanceof Asset ? this.getByAsset(criteria) : this.getByAlias(criteria); } - //*** HELPER METHODS ***// - - private getByAlias(alias: Alias): PayoutStrategy { - const strategy = this.strategies.get(alias); - - if (!strategy) throw new Error(`No PayoutStrategy found. Alias: ${alias}`); - - return strategy; - } - - private getByAsset(asset: Asset): PayoutStrategy { - const alias = this.getAlias(asset); - - return this.getByAlias(alias); - } - - private getAlias(asset: Asset): Alias { + getPayoutStrategyAlias(asset: Asset): Alias { const { blockchain, dexName: assetName, category: assetCategory } = asset; if (blockchain === Blockchain.BITCOIN) return Alias.BITCOIN; @@ -87,4 +71,20 @@ export class PayoutStrategiesFacade { if (assetCategory === AssetCategory.STOCK) return Alias.ETHEREUM_TOKEN; } } + + //*** HELPER METHODS ***// + + private getByAlias(alias: Alias): PayoutStrategy { + const strategy = this.strategies.get(alias); + + if (!strategy) throw new Error(`No PayoutStrategy found. Alias: ${alias}`); + + return strategy; + } + + private getByAsset(asset: Asset): PayoutStrategy { + const alias = this.getPayoutStrategyAlias(asset); + + return this.getByAlias(alias); + } } From a466663bcb9e00f2df7c4099d0e6a3b1afb3973b Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Tue, 4 Oct 2022 14:12:48 +0200 Subject: [PATCH 09/30] [DEV-622] implemented dex strategies for bitcoin and eth tokens --- .../dex/services/dex-bitcoin.service.ts | 42 ++++++++++++++++++- .../models/dex/services/dex-evm.service.ts | 21 +++++++--- .../impl/base/evm-token.strategy.ts | 4 +- .../check-liquidity/impl/bitcoin.strategy.ts | 4 +- .../impl/base/evm-crypto.strategy.ts | 17 +++----- .../impl/base/evm-token.strategy.ts | 18 +++++++- .../impl/bitcoin.strategy.ts | 20 ++++++++- 7 files changed, 104 insertions(+), 22 deletions(-) diff --git a/src/payment/models/dex/services/dex-bitcoin.service.ts b/src/payment/models/dex/services/dex-bitcoin.service.ts index db93bfced9..9baca9bb02 100644 --- a/src/payment/models/dex/services/dex-bitcoin.service.ts +++ b/src/payment/models/dex/services/dex-bitcoin.service.ts @@ -1,4 +1,44 @@ import { Injectable } from '@nestjs/common'; +import { BtcClient } from 'src/blockchain/ain/node/btc-client'; +import { NodeService, NodeType } from 'src/blockchain/ain/node/node.service'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { Util } from 'src/shared/util'; +import { LiquidityOrder } from '../entities/liquidity-order.entity'; +import { NotEnoughLiquidityException } from '../exceptions/not-enough-liquidity.exception'; +import { LiquidityOrderRepository } from '../repositories/liquidity-order.repository'; @Injectable() -export class DexBitcoinService {} +export class DexBitcoinService { + #client: BtcClient; + + constructor(private readonly liquidityOrderRepo: LiquidityOrderRepository, readonly nodeService: NodeService) { + nodeService.getConnectedNode(NodeType.BTC_OUTPUT).subscribe((client) => (this.#client = client)); + } + + async checkAvailableTargetLiquidity(amount: number): Promise { + const pendingAmount = await this.getPendingAmount(); + const availableAmount = await this.#client.getBalance(); + + this.checkLiquidity(amount, pendingAmount, +availableAmount); + + return amount; + } + + //*** HELPER METHODS ***// + + private async getPendingAmount(): Promise { + const pendingOrders = (await this.liquidityOrderRepo.find({ isReady: true, isComplete: false })).filter( + (o) => o.targetAsset.dexName === 'BTC' && o.targetAsset.blockchain === Blockchain.BITCOIN, + ); + + return Util.sumObj(pendingOrders, 'targetAmount'); + } + + private checkLiquidity(requiredAmount: number, pendingAmount: number, availableAmount: number): void { + if (requiredAmount > availableAmount - pendingAmount) { + throw new NotEnoughLiquidityException( + `Not enough liquidity of asset BTC. Trying to use ${requiredAmount} BTC worth liquidity. Available amount: ${availableAmount}. Pending amount: ${pendingAmount}`, + ); + } + } +} diff --git a/src/payment/models/dex/services/dex-evm.service.ts b/src/payment/models/dex/services/dex-evm.service.ts index 9b788892cb..e76fa97dd5 100644 --- a/src/payment/models/dex/services/dex-evm.service.ts +++ b/src/payment/models/dex/services/dex-evm.service.ts @@ -27,13 +27,17 @@ export abstract class DexEvmService { return amount; } - async checkTokenAvailability(token: string, amount: number): Promise { - const pendingAmount = await this.getPendingAmount(token); - const availableAmount = await this.#client.getTokenBalance(token); + async getAndCheckTokenAvailability( + referenceAsset: string, + referenceAmount: number, + targetAsset: string, + ): Promise { + // TODO - implement poolswap check or price request + const targetAmount = 1; - this.checkLiquidity(amount, pendingAmount, availableAmount, token); + await this.checkAssetAvailability(targetAsset, targetAmount); - return amount; + return targetAmount; } get _nativeCoin(): string { @@ -42,6 +46,13 @@ export abstract class DexEvmService { //*** HELPER METHODS ***// + private async checkAssetAvailability(asset: string, amount: number): Promise { + const pendingAmount = await this.getPendingAmount(asset); + const availableAmount = await this.#client.getTokenBalance(asset); + + this.checkLiquidity(amount, pendingAmount, availableAmount, asset); + } + private async getPendingAmount(assetName: string): Promise { const pendingOrders = (await this.liquidityOrderRepo.find({ isReady: true, isComplete: false })).filter( (o) => o.targetAsset.dexName === assetName && o.targetAsset.blockchain === this.blockchain, diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts index 61a9e01252..6f0dd254c1 100644 --- a/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts @@ -6,6 +6,8 @@ export class EvmTokenStrategy implements CheckLiquidityStrategy { constructor(protected readonly dexEvmService: DexEvmService) {} async checkLiquidity(request: LiquidityRequest): Promise { - return 0; + const { referenceAmount, referenceAsset, targetAsset } = request; + + return this.dexEvmService.getAndCheckTokenAvailability(referenceAsset, referenceAmount, targetAsset.dexName); } } diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/bitcoin.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/bitcoin.strategy.ts index 305ab3629e..6c3b4067af 100644 --- a/src/payment/models/dex/strategies/check-liquidity/impl/bitcoin.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/bitcoin.strategy.ts @@ -8,6 +8,8 @@ export class BitcoinStrategy implements CheckLiquidityStrategy { constructor(private readonly dexBtcService: DexBitcoinService) {} async checkLiquidity(request: LiquidityRequest): Promise { - return 0; + const { referenceAmount: bitcoinAmount } = request; + + return this.dexBtcService.checkAvailableTargetLiquidity(bitcoinAmount); } } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts index 99921172e2..d14626e85d 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts @@ -12,20 +12,13 @@ export class EvmCryptoStrategy extends PurchaseLiquidityStrategy { const { referenceAsset, referenceAmount, context, correlationId } = request; try { // should always throw, even if there is amount, additional check is done for API consistency and sending mail - if (referenceAsset === this.dexEvmService._nativeCoin) { - const amount = await this.dexEvmService.checkCoinAvailability(referenceAmount); + const amount = await this.dexEvmService.checkCoinAvailability(referenceAmount); - if (amount) { - throw new Error( - `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, - ); - } + if (amount) { + throw new Error( + `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, + ); } - - // throw by default, only native coin trading enabled - throw new Error( - `Only native coins are supported by EVM PurchaseLiquidity strategy. Provided reference asset: ${referenceAsset} Context: ${context}. CorrelationID: ${correlationId}`, - ); } catch (e) { await this.handlePurchaseLiquidityError(e, request); } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts index 50cc591718..c4de7eada9 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts @@ -9,6 +9,22 @@ export class EvmTokenStrategy extends PurchaseLiquidityStrategy { } async purchaseLiquidity(request: LiquidityRequest): Promise { - return; + const { referenceAsset, referenceAmount, targetAsset, context, correlationId } = request; + try { + // should always throw, even if there is amount, additional check is done for API consistency and sending mail + const amount = await this.dexEvmService.getAndCheckTokenAvailability( + referenceAsset, + referenceAmount, + targetAsset.dexName, + ); + + if (amount) { + throw new Error( + `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, + ); + } + } catch (e) { + await this.handlePurchaseLiquidityError(e, request); + } } } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/bitcoin.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/bitcoin.strategy.ts index dea7b6b717..c7630fb6d8 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/bitcoin.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/bitcoin.strategy.ts @@ -1,10 +1,28 @@ import { Injectable } from '@nestjs/common'; import { PurchaseLiquidityStrategy } from './base/purchase-liquidity.strategy'; import { LiquidityRequest } from '../../../interfaces'; +import { MailService } from 'src/shared/services/mail.service'; +import { DexBitcoinService } from '../../../services/dex-bitcoin.service'; @Injectable() export class BitcoinStrategy extends PurchaseLiquidityStrategy { + constructor(mailService: MailService, private readonly dexBtcService: DexBitcoinService) { + super(mailService); + } + async purchaseLiquidity(request: LiquidityRequest): Promise { - return; + const { referenceAsset, referenceAmount, context, correlationId } = request; + try { + // should always throw, even if there is amount, additional check is done for API consistency and sending mail + const amount = await this.dexBtcService.checkAvailableTargetLiquidity(referenceAmount); + + if (amount) { + throw new Error( + `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, + ); + } + } catch (e) { + await this.handlePurchaseLiquidityError(e, request); + } } } From 48abcc11beea00f0cca1ee05b04f85d6c7e74e35 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Tue, 4 Oct 2022 15:25:27 +0200 Subject: [PATCH 10/30] [DEV-622] implemented prepare strategy for bitcoin --- .../purchase-liquidity.facade.spec.ts | 3 +- .../prepare/__tests__/prepare.facade.spec.ts | 36 +++++++++++++------ .../impl/base/auto-confirm.strategy.ts | 20 +++++++++++ .../prepare/impl/base/evm.strategy.ts | 20 +++-------- .../prepare/impl/bitcoin.strategy.ts | 10 ++++++ .../strategies/prepare/prepare.facade.ts | 13 +++++-- 6 files changed, 73 insertions(+), 29 deletions(-) create mode 100644 src/payment/models/payout/strategies/prepare/impl/base/auto-confirm.strategy.ts create mode 100644 src/payment/models/payout/strategies/prepare/impl/bitcoin.strategy.ts diff --git a/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts b/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts index 7cb2afc9ad..ae1d865a98 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts @@ -9,6 +9,7 @@ import { SettingService } from 'src/shared/models/setting/setting.service'; import { MailService } from 'src/shared/services/mail.service'; import { LiquidityOrderFactory } from '../../../factories/liquidity-order.factory'; import { LiquidityOrderRepository } from '../../../repositories/liquidity-order.repository'; +import { DexBitcoinService } from '../../../services/dex-bitcoin.service'; import { DexBscService } from '../../../services/dex-bsc.service'; import { DexDeFiChainService } from '../../../services/dex-defichain.service'; import { DexService } from '../../../services/dex.service'; @@ -40,7 +41,7 @@ describe('PurchaseLiquidityStrategies', () => { nodeService = mock(); jest.spyOn(nodeService, 'getConnectedNode').mockImplementation(() => new BehaviorSubject(null)); - bitcoin = new BitcoinStrategy(mock()); + bitcoin = new BitcoinStrategy(mock(), mock()); bscCrypto = new BscCryptoStrategy(mock(), mock()); bscToken = new BscTokenStrategy(mock(), mock()); diff --git a/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts b/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts index 7563b6a7e1..9229e0bbc2 100644 --- a/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts +++ b/src/payment/models/payout/strategies/prepare/__tests__/prepare.facade.spec.ts @@ -4,12 +4,14 @@ import { DexService } from 'src/payment/models/dex/services/dex.service'; import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; +import { BitcoinStrategy } from '../impl/bitcoin.strategy'; import { BscStrategy } from '../impl/bsc.strategy'; import { DeFiChainStrategy } from '../impl/defichain.strategy'; import { EthereumStrategy } from '../impl/ethereum.strategy'; import { PrepareStrategiesFacade, PrepareStrategyAlias } from '../prepare.facade'; describe('PrepareStrategiesFacade', () => { + let bitcoin: BitcoinStrategy; let defichain: DeFiChainStrategy; let ethereum: EthereumStrategy; let bsc: BscStrategy; @@ -17,6 +19,7 @@ describe('PrepareStrategiesFacade', () => { let facade: PrepareStrategiesFacadeWrapper; beforeEach(() => { + bitcoin = new BitcoinStrategy(mock()); defichain = new DeFiChainStrategy( mock(), mock(), @@ -25,23 +28,30 @@ describe('PrepareStrategiesFacade', () => { ethereum = new EthereumStrategy(mock()); bsc = new BscStrategy(mock()); - facade = new PrepareStrategiesFacadeWrapper(defichain, ethereum, bsc); + facade = new PrepareStrategiesFacadeWrapper(bitcoin, defichain, ethereum, bsc); }); describe('#constructor(...)', () => { it('adds all prepareStrategies to a map', () => { - expect([...facade.getStrategies().entries()].length).toBe(3); + expect([...facade.getStrategies().entries()].length).toBe(4); + }); + + it('assigns strategies to all aliases', () => { + expect([...facade.getStrategies().entries()].length).toBe(Object.values(PrepareStrategyAlias).length); }); it('sets all required prepareStrategies aliases', () => { const aliases = [...facade.getStrategies().keys()]; + expect(aliases.includes(PrepareStrategyAlias.BITCOIN)).toBe(true); expect(aliases.includes(PrepareStrategyAlias.DEFICHAIN)).toBe(true); expect(aliases.includes(PrepareStrategyAlias.ETHEREUM)).toBe(true); expect(aliases.includes(PrepareStrategyAlias.BSC)).toBe(true); }); it('assigns proper prepareStrategies to aliases', () => { + expect(facade.getStrategies().get(PrepareStrategyAlias.BITCOIN)).toBeInstanceOf(BitcoinStrategy); + expect(facade.getStrategies().get(PrepareStrategyAlias.DEFICHAIN)).toBeInstanceOf(DeFiChainStrategy); expect(facade.getStrategies().get(PrepareStrategyAlias.ETHEREUM)).toBeInstanceOf(EthereumStrategy); @@ -52,6 +62,12 @@ describe('PrepareStrategiesFacade', () => { describe('#getPrepareStrategy(...)', () => { describe('getting strategy by Asset', () => { + it('gets BITCOIN strategy for BITCOIN', () => { + const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.BITCOIN })); + + expect(strategy).toBeInstanceOf(BitcoinStrategy); + }); + it('gets ETHEREUM strategy', () => { const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.ETHEREUM })); @@ -70,12 +86,6 @@ describe('PrepareStrategiesFacade', () => { expect(strategy).toBeInstanceOf(DeFiChainStrategy); }); - it('gets DEFICHAIN strategy for BITCOIN', () => { - const strategy = facade.getPrepareStrategy(createCustomAsset({ blockchain: Blockchain.BITCOIN })); - - expect(strategy).toBeInstanceOf(DeFiChainStrategy); - }); - it('fails to get strategy for non-supported Blockchain', () => { const testCall = () => facade.getPrepareStrategy(createCustomAsset({ blockchain: 'NewBlockchain' as Blockchain })); @@ -86,6 +96,12 @@ describe('PrepareStrategiesFacade', () => { }); describe('getting strategy by Alias', () => { + it('gets BITCOIN strategy', () => { + const strategy = facade.getPrepareStrategy(PrepareStrategyAlias.BITCOIN); + + expect(strategy).toBeInstanceOf(BitcoinStrategy); + }); + it('gets DEFICHAIN strategy', () => { const strategy = facade.getPrepareStrategy(PrepareStrategyAlias.DEFICHAIN); @@ -115,8 +131,8 @@ describe('PrepareStrategiesFacade', () => { }); class PrepareStrategiesFacadeWrapper extends PrepareStrategiesFacade { - constructor(defichain: DeFiChainStrategy, ethereum: EthereumStrategy, bsc: BscStrategy) { - super(defichain, ethereum, bsc); + constructor(bitcoin: BitcoinStrategy, defichain: DeFiChainStrategy, ethereum: EthereumStrategy, bsc: BscStrategy) { + super(bitcoin, defichain, ethereum, bsc); } getStrategies() { diff --git a/src/payment/models/payout/strategies/prepare/impl/base/auto-confirm.strategy.ts b/src/payment/models/payout/strategies/prepare/impl/base/auto-confirm.strategy.ts new file mode 100644 index 0000000000..baeb2e55c3 --- /dev/null +++ b/src/payment/models/payout/strategies/prepare/impl/base/auto-confirm.strategy.ts @@ -0,0 +1,20 @@ +import { PayoutOrder } from '../../../../entities/payout-order.entity'; +import { PayoutOrderRepository } from '../../../../repositories/payout-order.repository'; +import { PrepareStrategy } from './prepare.strategy'; + +export abstract class AutoConfirmStrategy implements PrepareStrategy { + constructor(protected readonly payoutOrderRepo: PayoutOrderRepository) {} + + async preparePayout(order: PayoutOrder): Promise { + order.preparationConfirmed(); + + await this.payoutOrderRepo.save(order); + } + + /** + * no payout preparation needed for ethereum + */ + async checkPreparationCompletion(): Promise { + return; + } +} diff --git a/src/payment/models/payout/strategies/prepare/impl/base/evm.strategy.ts b/src/payment/models/payout/strategies/prepare/impl/base/evm.strategy.ts index 6f2de01499..9d4290d339 100644 --- a/src/payment/models/payout/strategies/prepare/impl/base/evm.strategy.ts +++ b/src/payment/models/payout/strategies/prepare/impl/base/evm.strategy.ts @@ -1,20 +1,8 @@ -import { PayoutOrder } from '../../../../entities/payout-order.entity'; import { PayoutOrderRepository } from '../../../../repositories/payout-order.repository'; -import { PrepareStrategy } from './prepare.strategy'; +import { AutoConfirmStrategy } from './auto-confirm.strategy'; -export abstract class EvmStrategy implements PrepareStrategy { - constructor(protected readonly payoutOrderRepo: PayoutOrderRepository) {} - - async preparePayout(order: PayoutOrder): Promise { - order.preparationConfirmed(); - - await this.payoutOrderRepo.save(order); - } - - /** - * no payout preparation needed for ethereum - */ - async checkPreparationCompletion(): Promise { - return; +export abstract class EvmStrategy extends AutoConfirmStrategy { + constructor(payoutOrderRepo: PayoutOrderRepository) { + super(payoutOrderRepo); } } diff --git a/src/payment/models/payout/strategies/prepare/impl/bitcoin.strategy.ts b/src/payment/models/payout/strategies/prepare/impl/bitcoin.strategy.ts new file mode 100644 index 0000000000..5dcbc671c2 --- /dev/null +++ b/src/payment/models/payout/strategies/prepare/impl/bitcoin.strategy.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { AutoConfirmStrategy } from './base/auto-confirm.strategy'; + +@Injectable() +export class BitcoinStrategy extends AutoConfirmStrategy { + constructor(payoutOrderRepo: PayoutOrderRepository) { + super(payoutOrderRepo); + } +} diff --git a/src/payment/models/payout/strategies/prepare/prepare.facade.ts b/src/payment/models/payout/strategies/prepare/prepare.facade.ts index 3b5eb5a6b3..d0245d293a 100644 --- a/src/payment/models/payout/strategies/prepare/prepare.facade.ts +++ b/src/payment/models/payout/strategies/prepare/prepare.facade.ts @@ -2,11 +2,13 @@ import { Injectable } from '@nestjs/common'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; import { Asset } from 'src/shared/models/asset/asset.entity'; import { PrepareStrategy } from './impl/base/prepare.strategy'; +import { BitcoinStrategy } from './impl/bitcoin.strategy'; import { BscStrategy } from './impl/bsc.strategy'; import { DeFiChainStrategy } from './impl/defichain.strategy'; import { EthereumStrategy } from './impl/ethereum.strategy'; enum Alias { + BITCOIN = 'Bitcoin', DEFICHAIN = 'DeFiChain', ETHEREUM = 'Ethereum', BSC = 'Bsc', @@ -18,7 +20,13 @@ export { Alias as PrepareStrategyAlias }; export class PrepareStrategiesFacade { protected readonly strategies: Map = new Map(); - constructor(deFiChainStrategy: DeFiChainStrategy, ethereumStrategy: EthereumStrategy, bscStrategy: BscStrategy) { + constructor( + bitcoin: BitcoinStrategy, + deFiChainStrategy: DeFiChainStrategy, + ethereumStrategy: EthereumStrategy, + bscStrategy: BscStrategy, + ) { + this.strategies.set(Alias.BITCOIN, bitcoin); this.strategies.set(Alias.DEFICHAIN, deFiChainStrategy); this.strategies.set(Alias.ETHEREUM, ethereumStrategy); this.strategies.set(Alias.BSC, bscStrategy); @@ -47,8 +55,9 @@ export class PrepareStrategiesFacade { private getAlias(asset: Asset): Alias { const { blockchain } = asset; + if (blockchain === Blockchain.BITCOIN) return Alias.BITCOIN; if (blockchain === Blockchain.ETHEREUM) return Alias.ETHEREUM; if (blockchain === Blockchain.BINANCE_SMART_CHAIN) return Alias.BSC; - if (blockchain === Blockchain.DEFICHAIN || blockchain === Blockchain.BITCOIN) return Alias.DEFICHAIN; + if (blockchain === Blockchain.DEFICHAIN) return Alias.DEFICHAIN; } } From d30f9d6ad14acc3b268b1e7ff02554330ce5b3f5 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Wed, 5 Oct 2022 16:23:53 +0200 Subject: [PATCH 11/30] [DEV-622] added erc20 contract integration --- src/blockchain/shared/evm/abi/erc20.abi.json | 222 ++++++++++++++++++ src/blockchain/shared/evm/evm-client.ts | 28 ++- .../payout/services/payout-bitcoin.service.ts | 30 ++- .../payout/services/payout-evm.service.ts | 6 +- .../payout/impl/base/evm.strategy.ts | 2 +- src/shared/models/asset/asset.entity.ts | 4 +- 6 files changed, 282 insertions(+), 10 deletions(-) create mode 100644 src/blockchain/shared/evm/abi/erc20.abi.json diff --git a/src/blockchain/shared/evm/abi/erc20.abi.json b/src/blockchain/shared/evm/abi/erc20.abi.json new file mode 100644 index 0000000000..06b572ddc2 --- /dev/null +++ b/src/blockchain/shared/evm/abi/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/src/blockchain/shared/evm/evm-client.ts b/src/blockchain/shared/evm/evm-client.ts index 3181ff2c0f..617cdaaa5f 100644 --- a/src/blockchain/shared/evm/evm-client.ts +++ b/src/blockchain/shared/evm/evm-client.ts @@ -1,9 +1,12 @@ -import { ethers } from 'ethers'; +import { Contract, ethers } from 'ethers'; +import { Asset } from 'src/shared/models/asset/asset.entity'; +import ERC20ABI from './abi/erc20.abi.json'; export class EvmClient { #address: string; #provider: ethers.providers.JsonRpcProvider; #wallet: ethers.Wallet; + #erc20Tokens: Map; constructor(gatewayUrl: string, privateKey: string, address: string) { this.#provider = new ethers.providers.JsonRpcProvider(gatewayUrl); @@ -17,8 +20,8 @@ export class EvmClient { return parseFloat(ethers.utils.formatEther(balance)); } - async getTokenBalance(tokenName: string): Promise { - return 0; + async getTokenBalance(token: Asset): Promise { + return this.getERC20Contract(token.chainId).balanceOf(this.#address); } async sendNativeCrypto(address: string, amount: number): Promise { @@ -36,8 +39,10 @@ export class EvmClient { return tx.hash; } - async sendToken(address: string, tokenName: string, amount: number): Promise { - return 'tx hash'; + async sendToken(address: string, token: Asset, amount: number): Promise { + const contract = this.getERC20Contract(token.chainId); + + return await contract.transfer(address, ethers.utils.parseUnits(`${amount}`, 'ether')); } async isTxComplete(txHash: string): Promise { @@ -49,4 +54,17 @@ export class EvmClient { async getTx(txHash: string): Promise { return this.#provider.getTransaction(txHash); } + + //*** HELPER METHODS ***// + + private getERC20Contract(tokenAddress: string): Contract { + let token = this.#erc20Tokens.get(tokenAddress); + + if (!token) { + token = new ethers.Contract(tokenAddress, ERC20ABI, this.#wallet); + this.#erc20Tokens.set(tokenAddress, token); + } + + return token; + } } diff --git a/src/payment/models/payout/services/payout-bitcoin.service.ts b/src/payment/models/payout/services/payout-bitcoin.service.ts index 1768af3dfd..cc5e73462e 100644 --- a/src/payment/models/payout/services/payout-bitcoin.service.ts +++ b/src/payment/models/payout/services/payout-bitcoin.service.ts @@ -1,4 +1,32 @@ import { Injectable } from '@nestjs/common'; +import { BtcClient } from 'src/blockchain/ain/node/btc-client'; +import { NodeService, NodeType } from 'src/blockchain/ain/node/node.service'; + +export type PayoutGroup = { addressTo: string; amount: number }[]; @Injectable() -export class PayoutBitcoinService {} +export class PayoutBitcoinService { + #client: BtcClient; + + constructor(readonly nodeService: NodeService) { + nodeService.getConnectedNode(NodeType.BTC_OUTPUT).subscribe((client) => (this.#client = client)); + } + + async isHealthy(): Promise { + try { + return !!(await this.#client.getInfo()); + } catch { + return false; + } + } + + async sendUtxoToMany(payout: PayoutGroup): Promise { + return this.#client.sendUtxoToMany(payout); + } + + async checkPayoutCompletion(payoutTxId: string): Promise { + const transaction = await this.#client.getTx(payoutTxId); + + return transaction && transaction.blockhash && transaction.confirmations > 0; + } +} diff --git a/src/payment/models/payout/services/payout-evm.service.ts b/src/payment/models/payout/services/payout-evm.service.ts index ec67f940e2..1d3453d8cb 100644 --- a/src/payment/models/payout/services/payout-evm.service.ts +++ b/src/payment/models/payout/services/payout-evm.service.ts @@ -8,10 +8,14 @@ export abstract class PayoutEvmService { this.#client = service.getDefaultClient(); } - async send(address: string, amount: number): Promise { + async sendNativeCrypto(address: string, amount: number): Promise { return this.#client.sendNativeCrypto(address, amount); } + async sendToken(address: string, tokenName: string, amount: number): Promise { + return this.#client.sendToken(address, tokenName, amount); + } + async checkPayoutCompletion(txHash: string): Promise { return this.#client.isTxComplete(txHash); } diff --git a/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts b/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts index c6302f9df6..5e12108740 100644 --- a/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts @@ -12,7 +12,7 @@ export abstract class EvmStrategy implements PayoutStrategy { async doPayout(orders: PayoutOrder[]): Promise { for (const order of orders) { try { - const txId = await this.payoutEvmService.send(order.destinationAddress, order.amount); + const txId = await this.payoutEvmService.sendNativeCrypto(order.destinationAddress, order.amount); order.pendingPayout(txId); await this.payoutOrderRepo.save(order); diff --git a/src/shared/models/asset/asset.entity.ts b/src/shared/models/asset/asset.entity.ts index 3f5a231c75..39d8f1879a 100644 --- a/src/shared/models/asset/asset.entity.ts +++ b/src/shared/models/asset/asset.entity.ts @@ -19,8 +19,8 @@ export enum AssetCategory { unique: true, }) export class Asset extends IEntity { - @Column({ type: 'int', nullable: true }) - chainId: number; + @Column({ nullable: true }) + chainId: string; @Column({ length: 256 }) name: string; From 9ed096c27dcde1eeb745d10a17e7cf36d778cdce Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Thu, 6 Oct 2022 10:36:57 +0200 Subject: [PATCH 12/30] [DEV-622] basic test swap for evm --- src/blockchain/bsc/bsc-client.ts | 4 +- src/blockchain/bsc/bsc.service.ts | 4 +- src/blockchain/ethereum/ethereum-client.ts | 4 +- src/blockchain/ethereum/ethereum.service.ts | 5 +- .../shared/evm/abi/uniswap-router02.abi.json | 953 ++++++++++++++++++ src/blockchain/shared/evm/evm-client.ts | 34 +- src/blockchain/shared/evm/evm.service.ts | 7 +- src/config/config.ts | 2 + .../models/dex/services/dex-evm.service.ts | 16 +- .../impl/base/evm-token.strategy.ts | 2 +- .../impl/base/evm-token.strategy.ts | 2 +- .../payout/services/payout-evm.service.ts | 3 +- 12 files changed, 1001 insertions(+), 35 deletions(-) create mode 100644 src/blockchain/shared/evm/abi/uniswap-router02.abi.json diff --git a/src/blockchain/bsc/bsc-client.ts b/src/blockchain/bsc/bsc-client.ts index 2185a8b910..0c73377070 100644 --- a/src/blockchain/bsc/bsc-client.ts +++ b/src/blockchain/bsc/bsc-client.ts @@ -1,7 +1,7 @@ import { EvmClient } from '../shared/evm/evm-client'; export class BscClient extends EvmClient { - constructor(gatewayUrl: string, privateKey: string, address: string) { - super(gatewayUrl, privateKey, address); + constructor(gatewayUrl: string, privateKey: string, dfxAddress: string, swapContractAddress: string) { + super(gatewayUrl, privateKey, dfxAddress, swapContractAddress); } } diff --git a/src/blockchain/bsc/bsc.service.ts b/src/blockchain/bsc/bsc.service.ts index 9504d9e917..d7896fbbea 100644 --- a/src/blockchain/bsc/bsc.service.ts +++ b/src/blockchain/bsc/bsc.service.ts @@ -6,8 +6,8 @@ import { EvmService } from '../shared/evm/evm.service'; @Injectable() export class BscService extends EvmService { constructor() { - const { bscGatewayUrl, bscWalletAddress, bscWalletPrivateKey } = GetConfig().blockchain.bsc; + const { bscGatewayUrl, bscWalletAddress, bscWalletPrivateKey, pancakeRouterAddress } = GetConfig().blockchain.bsc; - super(bscGatewayUrl, '', bscWalletAddress, bscWalletPrivateKey, BscClient); + super(bscGatewayUrl, '', bscWalletAddress, bscWalletPrivateKey, pancakeRouterAddress, BscClient); } } diff --git a/src/blockchain/ethereum/ethereum-client.ts b/src/blockchain/ethereum/ethereum-client.ts index d84968ab29..3774ba6547 100644 --- a/src/blockchain/ethereum/ethereum-client.ts +++ b/src/blockchain/ethereum/ethereum-client.ts @@ -1,7 +1,7 @@ import { EvmClient } from '../shared/evm/evm-client'; export class EthereumClient extends EvmClient { - constructor(gatewayUrl: string, privateKey: string, address: string) { - super(gatewayUrl, privateKey, address); + constructor(gatewayUrl: string, privateKey: string, dfxAddress: string, swapContractAddress: string) { + super(gatewayUrl, privateKey, dfxAddress, swapContractAddress); } } diff --git a/src/blockchain/ethereum/ethereum.service.ts b/src/blockchain/ethereum/ethereum.service.ts index a2a48cc366..cf2d41f231 100644 --- a/src/blockchain/ethereum/ethereum.service.ts +++ b/src/blockchain/ethereum/ethereum.service.ts @@ -6,8 +6,9 @@ import { EvmService } from '../shared/evm/evm.service'; @Injectable() export class EthereumService extends EvmService { constructor() { - const { ethGatewayUrl, ethApiKey, ethWalletAddress, ethWalletPrivateKey } = GetConfig().blockchain.ethereum; + const { ethGatewayUrl, ethApiKey, ethWalletAddress, ethWalletPrivateKey, uniswapV2Router02Address } = + GetConfig().blockchain.ethereum; - super(ethGatewayUrl, ethApiKey, ethWalletAddress, ethWalletPrivateKey, EthereumClient); + super(ethGatewayUrl, ethApiKey, ethWalletAddress, ethWalletPrivateKey, uniswapV2Router02Address, EthereumClient); } } diff --git a/src/blockchain/shared/evm/abi/uniswap-router02.abi.json b/src/blockchain/shared/evm/abi/uniswap-router02.abi.json new file mode 100644 index 0000000000..55ca7a7317 --- /dev/null +++ b/src/blockchain/shared/evm/abi/uniswap-router02.abi.json @@ -0,0 +1,953 @@ +[ + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETHSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapETHForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/blockchain/shared/evm/evm-client.ts b/src/blockchain/shared/evm/evm-client.ts index 617cdaaa5f..7fefd4a751 100644 --- a/src/blockchain/shared/evm/evm-client.ts +++ b/src/blockchain/shared/evm/evm-client.ts @@ -1,34 +1,37 @@ import { Contract, ethers } from 'ethers'; import { Asset } from 'src/shared/models/asset/asset.entity'; -import ERC20ABI from './abi/erc20.abi.json'; +import ERC20_ABI from './abi/erc20.abi.json'; +import UNISWAP_ROUTER_02_ABI from './abi/erc20.abi.json'; export class EvmClient { - #address: string; + #dfxAddress: string; #provider: ethers.providers.JsonRpcProvider; #wallet: ethers.Wallet; + #router: Contract; #erc20Tokens: Map; - constructor(gatewayUrl: string, privateKey: string, address: string) { + constructor(gatewayUrl: string, privateKey: string, dfxAddress: string, swapContractAddress: string) { this.#provider = new ethers.providers.JsonRpcProvider(gatewayUrl); this.#wallet = new ethers.Wallet(privateKey, this.#provider); - this.#address = address; + this.#dfxAddress = dfxAddress; + this.#router = new ethers.Contract(swapContractAddress, UNISWAP_ROUTER_02_ABI, this.#wallet); } async getNativeCryptoBalance(): Promise { - const balance = await this.#provider.getBalance(this.#address); + const balance = await this.#provider.getBalance(this.#dfxAddress); return parseFloat(ethers.utils.formatEther(balance)); } async getTokenBalance(token: Asset): Promise { - return this.getERC20Contract(token.chainId).balanceOf(this.#address); + return this.getERC20Contract(token.chainId).balanceOf(this.#dfxAddress); } async sendNativeCrypto(address: string, amount: number): Promise { const gasPrice = await this.#provider.getGasPrice(); const tx = await this.#wallet.sendTransaction({ - from: this.#address, + from: this.#dfxAddress, to: address, value: ethers.utils.parseUnits(`${amount}`, 'ether'), gasPrice, @@ -55,16 +58,23 @@ export class EvmClient { return this.#provider.getTransaction(txHash); } + async testSwap(tokenFrom: string, tokenTo: Asset, amount: number): Promise { + const inputAmount = ethers.utils.parseUnits(`${amount}`, 'ether'); + const outputAmounts = await this.#router.getAmountsOut(inputAmount, [tokenTo.chainId]); + + return outputAmounts[0]; + } + //*** HELPER METHODS ***// private getERC20Contract(tokenAddress: string): Contract { - let token = this.#erc20Tokens.get(tokenAddress); + let tokenContract = this.#erc20Tokens.get(tokenAddress); - if (!token) { - token = new ethers.Contract(tokenAddress, ERC20ABI, this.#wallet); - this.#erc20Tokens.set(tokenAddress, token); + if (!tokenContract) { + tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, this.#wallet); + this.#erc20Tokens.set(tokenAddress, tokenContract); } - return token; + return tokenContract; } } diff --git a/src/blockchain/shared/evm/evm.service.ts b/src/blockchain/shared/evm/evm.service.ts index 40b9db6c93..92c182098b 100644 --- a/src/blockchain/shared/evm/evm.service.ts +++ b/src/blockchain/shared/evm/evm.service.ts @@ -8,9 +8,12 @@ export abstract class EvmService { apiKey: string, walletAddress: string, walletPrivateKey: string, - client: { new (gatewayUrl: string, privateKey: string, address: string): EvmClient }, + swapContractAddress: string, + client: { + new (gatewayUrl: string, privateKey: string, dfxAddress: string, swapContractAddress: string): EvmClient; + }, ) { - this.client = new client(`${gatewayUrl}/${apiKey}`, walletPrivateKey, walletAddress); + this.client = new client(`${gatewayUrl}/${apiKey}`, walletPrivateKey, walletAddress, swapContractAddress); } getDefaultClient(): T { diff --git a/src/config/config.ts b/src/config/config.ts index 189b2dec37..358adc6f1f 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -216,11 +216,13 @@ export class Configuration { ethWalletPrivateKey: process.env.ETH_WALLET_PRIVATE_KEY, ethGatewayUrl: process.env.ETH_GATEWAY_URL, ethApiKey: process.env.ETH_API_KEY, + uniswapV2Router02Address: '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', }, bsc: { bscWalletAddress: process.env.BSC_WALLET_ADDRESS, bscWalletPrivateKey: process.env.BSC_WALLET_PRIVATE_KEY, bscGatewayUrl: process.env.BSC_GATEWAY_URL, + pancakeRouterAddress: '0x10ED43C718714eb63d5aA57B78B54704E256024E', }, }; diff --git a/src/payment/models/dex/services/dex-evm.service.ts b/src/payment/models/dex/services/dex-evm.service.ts index e76fa97dd5..d9009e3656 100644 --- a/src/payment/models/dex/services/dex-evm.service.ts +++ b/src/payment/models/dex/services/dex-evm.service.ts @@ -1,6 +1,7 @@ import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; import { EvmClient } from 'src/blockchain/shared/evm/evm-client'; import { EvmService } from 'src/blockchain/shared/evm/evm.service'; +import { Asset } from 'src/shared/models/asset/asset.entity'; import { Util } from 'src/shared/util'; import { LiquidityOrder } from '../entities/liquidity-order.entity'; import { NotEnoughLiquidityException } from '../exceptions/not-enough-liquidity.exception'; @@ -27,13 +28,8 @@ export abstract class DexEvmService { return amount; } - async getAndCheckTokenAvailability( - referenceAsset: string, - referenceAmount: number, - targetAsset: string, - ): Promise { - // TODO - implement poolswap check or price request - const targetAmount = 1; + async getAndCheckTokenAvailability(sourceAsset: string, sourceAmount: number, targetAsset: Asset): Promise { + const targetAmount = await this.#client.testSwap(sourceAsset, targetAsset, sourceAmount); await this.checkAssetAvailability(targetAsset, targetAmount); @@ -46,11 +42,11 @@ export abstract class DexEvmService { //*** HELPER METHODS ***// - private async checkAssetAvailability(asset: string, amount: number): Promise { - const pendingAmount = await this.getPendingAmount(asset); + private async checkAssetAvailability(asset: Asset, amount: number): Promise { + const pendingAmount = await this.getPendingAmount(asset.dexName); const availableAmount = await this.#client.getTokenBalance(asset); - this.checkLiquidity(amount, pendingAmount, availableAmount, asset); + this.checkLiquidity(amount, pendingAmount, availableAmount, asset.dexName); } private async getPendingAmount(assetName: string): Promise { diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts index 6f0dd254c1..2327f110b1 100644 --- a/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-token.strategy.ts @@ -8,6 +8,6 @@ export class EvmTokenStrategy implements CheckLiquidityStrategy { async checkLiquidity(request: LiquidityRequest): Promise { const { referenceAmount, referenceAsset, targetAsset } = request; - return this.dexEvmService.getAndCheckTokenAvailability(referenceAsset, referenceAmount, targetAsset.dexName); + return this.dexEvmService.getAndCheckTokenAvailability(referenceAsset, referenceAmount, targetAsset); } } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts index c4de7eada9..993229010b 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts @@ -15,7 +15,7 @@ export class EvmTokenStrategy extends PurchaseLiquidityStrategy { const amount = await this.dexEvmService.getAndCheckTokenAvailability( referenceAsset, referenceAmount, - targetAsset.dexName, + targetAsset, ); if (amount) { diff --git a/src/payment/models/payout/services/payout-evm.service.ts b/src/payment/models/payout/services/payout-evm.service.ts index 1d3453d8cb..64c9a19f9a 100644 --- a/src/payment/models/payout/services/payout-evm.service.ts +++ b/src/payment/models/payout/services/payout-evm.service.ts @@ -1,5 +1,6 @@ import { EvmClient } from 'src/blockchain/shared/evm/evm-client'; import { EvmService } from 'src/blockchain/shared/evm/evm.service'; +import { Asset } from 'src/shared/models/asset/asset.entity'; export abstract class PayoutEvmService { #client: EvmClient; @@ -12,7 +13,7 @@ export abstract class PayoutEvmService { return this.#client.sendNativeCrypto(address, amount); } - async sendToken(address: string, tokenName: string, amount: number): Promise { + async sendToken(address: string, tokenName: Asset, amount: number): Promise { return this.#client.sendToken(address, tokenName, amount); } From d06636f44a26552dc9be61cfce0279ca71dcc8f8 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Thu, 6 Oct 2022 10:51:58 +0200 Subject: [PATCH 13/30] [DEV-622] fixed abi import and denomination of erc20 tokens --- src/blockchain/shared/evm/evm-client.ts | 6 +++--- src/payment/models/payout/payout.module.ts | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/blockchain/shared/evm/evm-client.ts b/src/blockchain/shared/evm/evm-client.ts index 7fefd4a751..7c046d5ced 100644 --- a/src/blockchain/shared/evm/evm-client.ts +++ b/src/blockchain/shared/evm/evm-client.ts @@ -1,7 +1,7 @@ import { Contract, ethers } from 'ethers'; import { Asset } from 'src/shared/models/asset/asset.entity'; -import ERC20_ABI from './abi/erc20.abi.json'; -import UNISWAP_ROUTER_02_ABI from './abi/erc20.abi.json'; +import * as ERC20_ABI from './abi/erc20.abi.json'; +import * as UNISWAP_ROUTER_02_ABI from './abi/erc20.abi.json'; export class EvmClient { #dfxAddress: string; @@ -62,7 +62,7 @@ export class EvmClient { const inputAmount = ethers.utils.parseUnits(`${amount}`, 'ether'); const outputAmounts = await this.#router.getAmountsOut(inputAmount, [tokenTo.chainId]); - return outputAmounts[0]; + return +ethers.utils.parseUnits(outputAmounts[0], 'wei'); } //*** HELPER METHODS ***// diff --git a/src/payment/models/payout/payout.module.ts b/src/payment/models/payout/payout.module.ts index e625f16a12..7d03e77162 100644 --- a/src/payment/models/payout/payout.module.ts +++ b/src/payment/models/payout/payout.module.ts @@ -22,6 +22,7 @@ import { DeFiChainDfiStrategy as DeFiChainDfiStrategyPO } from './strategies/pay import { DeFiChainTokenStrategy as DeFiChainTokenStrategyPO } from './strategies/payout/impl/defichain-token.strategy'; import { EthereumCryptoStrategy as EthereumCryptoStrategyPO } from './strategies/payout/impl/ethereum-crypto.strategy'; import { EthereumTokenStrategy as EthereumTokenStrategyPO } from './strategies/payout/impl/ethereum-token.strategy'; +import { BitcoinStrategy as BitcoinStrategyPR } from './strategies/prepare/impl/bitcoin.strategy'; import { BscStrategy as BscStrategyPR } from './strategies/prepare/impl/bsc.strategy'; import { DeFiChainStrategy as DeFiChainStrategyPR } from './strategies/prepare/impl/defichain.strategy'; import { EthereumStrategy as EthereumStrategyPR } from './strategies/prepare/impl/ethereum.strategy'; @@ -53,6 +54,7 @@ import { EthereumStrategy as EthereumStrategyPR } from './strategies/prepare/imp DeFiChainTokenStrategyPO, EthereumCryptoStrategyPO, EthereumTokenStrategyPO, + BitcoinStrategyPR, BscStrategyPR, DeFiChainStrategyPR, EthereumStrategyPR, From 481ef156f6578d575671aac03826681cb568a70a Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Thu, 6 Oct 2022 13:06:20 +0200 Subject: [PATCH 14/30] [DEV-622] implemented new reference asset rules --- .../__tests__/buy-crypto.entity.spec.ts | 53 +++++++++++++++++-- .../buy-crypto/entities/buy-crypto.entity.ts | 10 ++++ .../impl/base/evm-crypto.strategy.ts | 17 ++++-- .../impl/base/evm-token.strategy.ts | 48 +++++++++++++---- .../pricing/services/pricing.service.ts | 1 + 5 files changed, 111 insertions(+), 18 deletions(-) diff --git a/src/payment/models/buy-crypto/entities/__tests__/buy-crypto.entity.spec.ts b/src/payment/models/buy-crypto/entities/__tests__/buy-crypto.entity.spec.ts index 3d44d95662..91845cb9e6 100644 --- a/src/payment/models/buy-crypto/entities/__tests__/buy-crypto.entity.spec.ts +++ b/src/payment/models/buy-crypto/entities/__tests__/buy-crypto.entity.spec.ts @@ -179,10 +179,10 @@ describe('BuyCrypto', () => { expect(entity.outputReferenceAsset).toBe('USDT'); }); - it('assigns outputReferenceAsset to ETH, on Ethereum blockchain', () => { + it('assigns outputReferenceAsset to ETH, on Ethereum blockchain when outputAsset is not DFI', () => { const entity = createCustomBuyCrypto({ outputReferenceAsset: undefined, - buy: createCustomBuy({ asset: createCustomAsset({ blockchain: Blockchain.ETHEREUM }) }), + buy: createCustomBuy({ asset: createCustomAsset({ blockchain: Blockchain.ETHEREUM, dexName: 'GOOGL' }) }), }); expect(entity.outputReferenceAsset).toBeUndefined(); @@ -192,10 +192,25 @@ describe('BuyCrypto', () => { expect(entity.outputReferenceAsset).toBe('ETH'); }); - it('assigns outputReferenceAsset to BNB, on BSC blockchain', () => { + it('assigns outputReferenceAsset to outputAsset, on Ethereum blockchain when outputAsset is DFI', () => { const entity = createCustomBuyCrypto({ outputReferenceAsset: undefined, - buy: createCustomBuy({ asset: createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN }) }), + buy: createCustomBuy({ asset: createCustomAsset({ blockchain: Blockchain.ETHEREUM, dexName: 'DFI' }) }), + }); + + expect(entity.outputReferenceAsset).toBeUndefined(); + + entity.defineAssetExchangePair(); + + expect(entity.outputReferenceAsset).toBe('DFI'); + }); + + it('assigns outputReferenceAsset to BNB, on BSC blockchain when outputAsset is not DFI | BUSD', () => { + const entity = createCustomBuyCrypto({ + outputReferenceAsset: undefined, + buy: createCustomBuy({ + asset: createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, dexName: 'GOOGL' }), + }), }); expect(entity.outputReferenceAsset).toBeUndefined(); @@ -205,6 +220,36 @@ describe('BuyCrypto', () => { expect(entity.outputReferenceAsset).toBe('BNB'); }); + it('assigns outputReferenceAsset to outputAsset, on BSC blockchain when outputAsset is DFI', () => { + const entity = createCustomBuyCrypto({ + outputReferenceAsset: undefined, + buy: createCustomBuy({ + asset: createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, dexName: 'DFI' }), + }), + }); + + expect(entity.outputReferenceAsset).toBeUndefined(); + + entity.defineAssetExchangePair(); + + expect(entity.outputReferenceAsset).toBe('DFI'); + }); + + it('assigns outputReferenceAsset to outputAsset, on BSC blockchain when outputAsset is BUSD', () => { + const entity = createCustomBuyCrypto({ + outputReferenceAsset: undefined, + buy: createCustomBuy({ + asset: createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, dexName: 'BUSD' }), + }), + }); + + expect(entity.outputReferenceAsset).toBeUndefined(); + + entity.defineAssetExchangePair(); + + expect(entity.outputReferenceAsset).toBe('BUSD'); + }); + it('defaults outputReferenceAsset to BTC on Bitcoin blockchain', () => { const entity = createCustomBuyCrypto({ outputReferenceAsset: undefined, diff --git a/src/payment/models/buy-crypto/entities/buy-crypto.entity.ts b/src/payment/models/buy-crypto/entities/buy-crypto.entity.ts index 096c41d6ae..bd77950e94 100644 --- a/src/payment/models/buy-crypto/entities/buy-crypto.entity.ts +++ b/src/payment/models/buy-crypto/entities/buy-crypto.entity.ts @@ -134,10 +134,20 @@ export class BuyCrypto extends IEntity { switch (this.target.asset.blockchain) { case Blockchain.ETHEREUM: + if (this.outputAsset === 'DFI') { + this.outputReferenceAsset = this.outputAsset; + break; + } + this.outputReferenceAsset = 'ETH'; break; case Blockchain.BINANCE_SMART_CHAIN: + if (['DFI', 'BUSD'].includes(this.outputAsset)) { + this.outputReferenceAsset = this.outputAsset; + break; + } + this.outputReferenceAsset = 'BNB'; break; diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts index d14626e85d..bf91d24c1b 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts @@ -12,13 +12,20 @@ export class EvmCryptoStrategy extends PurchaseLiquidityStrategy { const { referenceAsset, referenceAmount, context, correlationId } = request; try { // should always throw, even if there is amount, additional check is done for API consistency and sending mail - const amount = await this.dexEvmService.checkCoinAvailability(referenceAmount); + if (referenceAsset === this.dexEvmService._nativeCoin) { + const amount = await this.dexEvmService.checkCoinAvailability(referenceAmount); - if (amount) { - throw new Error( - `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, - ); + if (amount) { + throw new Error( + `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, + ); + } } + + // throw by default, only native coin is enabled as a referenceAsset + throw new Error( + `Only native coin reference is supported by EVM PurchaseLiquidity strategy. Provided reference asset: ${referenceAsset} Context: ${context}. CorrelationID: ${correlationId}`, + ); } catch (e) { await this.handlePurchaseLiquidityError(e, request); } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts index 993229010b..8d0c0e6870 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts @@ -10,21 +10,51 @@ export class EvmTokenStrategy extends PurchaseLiquidityStrategy { async purchaseLiquidity(request: LiquidityRequest): Promise { const { referenceAsset, referenceAmount, targetAsset, context, correlationId } = request; + try { // should always throw, even if there is amount, additional check is done for API consistency and sending mail - const amount = await this.dexEvmService.getAndCheckTokenAvailability( - referenceAsset, - referenceAmount, - targetAsset, - ); - - if (amount) { - throw new Error( - `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, + if (referenceAsset === this.dexEvmService._nativeCoin) { + const amount = await this.dexEvmService.getAndCheckTokenAvailability( + referenceAsset, + referenceAmount, + targetAsset, ); + + if (amount) { + throw new Error( + `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, + ); + } } + + // throw by default, only native coin is enabled as a referenceAsset + throw new Error( + `Only native coin reference is supported by EVM PurchaseLiquidity strategy. Provided reference asset: ${referenceAsset} Context: ${context}. CorrelationID: ${correlationId}`, + ); } catch (e) { await this.handlePurchaseLiquidityError(e, request); } } } + +// const { referenceAsset, referenceAmount, context, correlationId } = request; +// try { +// // should always throw, even if there is amount, additional check is done for API consistency and sending mail +// if (referenceAsset === this.dexEvmService._nativeCoin) { +// const amount = await this.dexEvmService.checkCoinAvailability(referenceAmount); + +// if (amount) { +// throw new Error( +// `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, +// ); +// } +// } + +// // throw by default, only native coin trading enabled +// throw new Error( +// `Only native coins are supported by EVM PurchaseLiquidity strategy. Provided reference asset: ${referenceAsset} Context: ${context}. CorrelationID: ${correlationId}`, +// ); +// } catch (e) { +// await this.handlePurchaseLiquidityError(e, request); +// } +// } diff --git a/src/payment/models/pricing/services/pricing.service.ts b/src/payment/models/pricing/services/pricing.service.ts index 8163baadaf..8d01772a31 100644 --- a/src/payment/models/pricing/services/pricing.service.ts +++ b/src/payment/models/pricing/services/pricing.service.ts @@ -25,6 +25,7 @@ export enum PricingPathAlias { MATCHING_FIAT_TO_USD_STABLE_COIN = 'MatchingFiatToUSDStableCoin', NON_MATCHING_FIAT_TO_USD_STABLE_COIN = 'NonMatchingFiatToUSDStableCoin', NON_MATCHING_USD_STABLE_COIN_TO_USD_STABLE_COIN = 'NonMatchingUSDStableCoinToUSDStableCoin', + // TODO -DFI case separately through testPoolSwap -> DEX } @Injectable() From c1b996054855fa709c2c8d973154de97d12785c7 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Thu, 6 Oct 2022 14:08:36 +0200 Subject: [PATCH 15/30] [DEV-622] implemented btc to dfi pricing path --- .../dex/entities/liquidity-order.entity.ts | 1 + src/payment/models/dex/interfaces/index.ts | 6 +++ .../dex/services/dex-defichain.service.ts | 6 ++- .../impl/defichain-default.strategy.ts | 4 +- .../__tests__/pricing.integration.spec.ts | 52 +++++++++++++++++++ src/payment/models/pricing/enums/index.ts | 1 + src/payment/models/pricing/pricing.module.ts | 3 +- .../services/dfi-pricing-dex.service.ts | 43 +++++++++++++++ .../pricing/services/pricing.service.ts | 29 ++++++++++- 9 files changed, 139 insertions(+), 6 deletions(-) create mode 100644 src/payment/models/pricing/services/dfi-pricing-dex.service.ts diff --git a/src/payment/models/dex/entities/liquidity-order.entity.ts b/src/payment/models/dex/entities/liquidity-order.entity.ts index aa6fd6d324..2c28160215 100644 --- a/src/payment/models/dex/entities/liquidity-order.entity.ts +++ b/src/payment/models/dex/entities/liquidity-order.entity.ts @@ -7,6 +7,7 @@ export enum LiquidityOrderContext { BUY_CRYPTO = 'BuyCrypto', STAKING_REWARD = 'StakingReward', CREATE_POOL_PAIR = 'CreatePoolPair', + PRICING = 'Pricing', } export enum LiquidityOrderType { diff --git a/src/payment/models/dex/interfaces/index.ts b/src/payment/models/dex/interfaces/index.ts index f0567694f5..de3344dec2 100644 --- a/src/payment/models/dex/interfaces/index.ts +++ b/src/payment/models/dex/interfaces/index.ts @@ -7,6 +7,12 @@ export interface LiquidityRequest { referenceAsset: string; referenceAmount: number; targetAsset: Asset; + options?: LiquidityRequestOptions; +} + +export interface LiquidityRequestOptions { + bypassAvailabilityCheck?: boolean; + bypassSlippageProtection?: boolean; } export interface TransferRequest { diff --git a/src/payment/models/dex/services/dex-defichain.service.ts b/src/payment/models/dex/services/dex-defichain.service.ts index 84dde21e2b..fca67976d1 100644 --- a/src/payment/models/dex/services/dex-defichain.service.ts +++ b/src/payment/models/dex/services/dex-defichain.service.ts @@ -31,15 +31,17 @@ export class DexDeFiChainService { sourceAmount: number, targetAsset: string, maxSlippage: number, + bypassAvailabilityCheck?: boolean, + bypassSlippageProtection?: boolean, ): Promise { const targetAmount = targetAsset === sourceAsset ? sourceAmount : await this.#dexClient.testCompositeSwap(sourceAsset, targetAsset, sourceAmount); - await this.checkAssetAvailability(targetAsset, targetAmount); + !bypassAvailabilityCheck && (await this.checkAssetAvailability(targetAsset, targetAmount)); - if ((await this.settingService.get('slippage-protection')) === 'on') { + if ((await this.settingService.get('slippage-protection')) === 'on' && !bypassSlippageProtection) { await this.checkTestSwapPriceSlippage(sourceAsset, sourceAmount, targetAsset, targetAmount, maxSlippage); } diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/defichain-default.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/defichain-default.strategy.ts index 19f84e3081..56018a1b97 100644 --- a/src/payment/models/dex/strategies/check-liquidity/impl/defichain-default.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/defichain-default.strategy.ts @@ -9,7 +9,7 @@ export class DeFiChainDefaultStrategy implements CheckLiquidityStrategy { constructor(private readonly dexDeFiChainService: DexDeFiChainService) {} async checkLiquidity(request: LiquidityRequest): Promise { - const { referenceAsset, referenceAmount, targetAsset } = request; + const { referenceAsset, referenceAmount, targetAsset, options } = request; // calculating how much targetAmount is needed and if it's available on the node return this.dexDeFiChainService.getAndCheckAvailableTargetLiquidity( @@ -17,6 +17,8 @@ export class DeFiChainDefaultStrategy implements CheckLiquidityStrategy { referenceAmount, targetAsset.dexName, LiquidityOrder.getMaxPriceSlippage(targetAsset.dexName), + options?.bypassAvailabilityCheck, + options?.bypassSlippageProtection, ); } } diff --git a/src/payment/models/pricing/__tests__/pricing.integration.spec.ts b/src/payment/models/pricing/__tests__/pricing.integration.spec.ts index 0d3f7a9314..3de0adec2f 100644 --- a/src/payment/models/pricing/__tests__/pricing.integration.spec.ts +++ b/src/payment/models/pricing/__tests__/pricing.integration.spec.ts @@ -9,6 +9,7 @@ import { CurrencyService } from '../../exchange/services/currency.service'; import { FixerService } from '../../exchange/services/fixer.service'; import { FtxService } from '../../exchange/services/ftx.service'; import { KrakenService } from '../../exchange/services/kraken.service'; +import { DfiPricingDexService } from '../services/dfi-pricing-dex.service'; import { PricingService } from '../services/pricing.service'; describe('Pricing Module Integration Tests', () => { @@ -20,6 +21,7 @@ describe('Pricing Module Integration Tests', () => { let ftxService: FtxService; let currencyService: CurrencyService; let fixerService: FixerService; + let dfiDexService: DfiPricingDexService; let krakenServiceGetPriceSpy: jest.SpyInstance; let binanceServiceGetPriceSpy: jest.SpyInstance; @@ -28,6 +30,7 @@ describe('Pricing Module Integration Tests', () => { let ftxServiceGetPriceSpy: jest.SpyInstance; let currencyServiceGetPriceSpy: jest.SpyInstance; let fixerServiceGetPriceSpy: jest.SpyInstance; + let dfiDexServiceGetPriceSpy: jest.SpyInstance; let service: PricingService; @@ -40,6 +43,7 @@ describe('Pricing Module Integration Tests', () => { ftxService = mock({ name: 'Ftx' }); currencyService = mock({ name: 'CurrencyService' }); fixerService = mock({ name: 'FixerService' }); + dfiDexService = mock({ name: 'DfiPricingDexService' }); service = new PricingService( mailService, @@ -50,6 +54,7 @@ describe('Pricing Module Integration Tests', () => { ftxService, currencyService, fixerService, + dfiDexService, ); krakenServiceGetPriceSpy = jest.spyOn(krakenService, 'getPrice'); @@ -59,6 +64,7 @@ describe('Pricing Module Integration Tests', () => { ftxServiceGetPriceSpy = jest.spyOn(ftxService, 'getPrice'); currencyServiceGetPriceSpy = jest.spyOn(currencyService, 'getPrice'); fixerServiceGetPriceSpy = jest.spyOn(fixerService, 'getPrice'); + dfiDexServiceGetPriceSpy = jest.spyOn(dfiDexService, 'getPrice'); }); afterEach(() => { @@ -69,6 +75,7 @@ describe('Pricing Module Integration Tests', () => { ftxServiceGetPriceSpy.mockClear(); currencyServiceGetPriceSpy.mockClear(); fixerServiceGetPriceSpy.mockClear(); + dfiDexServiceGetPriceSpy.mockClear(); }); it('calculates price path for MATCHING_ASSETS', async () => { @@ -359,4 +366,49 @@ describe('Pricing Module Integration Tests', () => { expect(result.path[0].timestamp).toBeInstanceOf(Date); }); + + it('calculates price path for FIAT_TO_DFI', async () => { + krakenServiceGetPriceSpy = jest + .spyOn(krakenService, 'getPrice') + .mockImplementationOnce(async (source: string, target: string) => + createCustomPrice({ source, target, price: 0.000049 }), + ); + + dfiDexServiceGetPriceSpy = jest + .spyOn(dfiDexService, 'getPrice') + .mockImplementationOnce(async (source: string, target: string) => + createCustomPrice({ source, target, price: 23111 }), + ); + + const request = { from: 'EUR', to: 'DFI' }; + const result = await service.getPrice(request); + + expect(result.price).toBeInstanceOf(Price); + expect(result.price.source).toBe('EUR'); + expect(result.price.target).toBe('DFI'); + expect(result.price.price).toBe(1.132439); + + expect(Array.isArray(result.path)).toBe(true); + expect(result.path.length).toBe(2); + + expect(result.path[0].provider).toBe('Kraken'); + + expect(result.path[0].price).toBeInstanceOf(Price); + expect(result.path[0].price.source).toBe('EUR'); + expect(result.path[0].price.target).toBe('BTC'); + expect(result.path[0].price.price).toBe(0.000049); + + expect(result.path[0].timestamp).toBeInstanceOf(Date); + + expect(result.path[1].provider).toBe('DfiPricingDexService'); + + expect(result.path[1].price).toBeInstanceOf(Price); + expect(result.path[1].price.source).toBe('BTC'); + expect(result.path[1].price.target).toBe('DFI'); + expect(result.path[1].price.price).toBe(23111); + + expect(result.path[1].timestamp).toBeInstanceOf(Date); + + expect(result.path[1].provider).toBe('DfiPricingDexService'); + }); }); diff --git a/src/payment/models/pricing/enums/index.ts b/src/payment/models/pricing/enums/index.ts index a9255f3611..56129fa986 100644 --- a/src/payment/models/pricing/enums/index.ts +++ b/src/payment/models/pricing/enums/index.ts @@ -8,6 +8,7 @@ export enum Fiat { export enum USDStableCoin { USDC = 'USDC', USDT = 'USDT', + BUSD = 'BUSD', } export enum Altcoin { diff --git a/src/payment/models/pricing/pricing.module.ts b/src/payment/models/pricing/pricing.module.ts index 3866e0c399..cf2d4a8314 100644 --- a/src/payment/models/pricing/pricing.module.ts +++ b/src/payment/models/pricing/pricing.module.ts @@ -2,12 +2,13 @@ import { Module } from '@nestjs/common'; import { SharedModule } from 'src/shared/shared.module'; import { DexModule } from '../dex/dex.module'; import { ExchangeModule } from '../exchange/exchange.module'; +import { DfiPricingDexService } from './services/dfi-pricing-dex.service'; import { PricingService } from './services/pricing.service'; @Module({ imports: [SharedModule, ExchangeModule, DexModule], controllers: [], - providers: [PricingService], + providers: [PricingService, DfiPricingDexService], exports: [PricingService], }) export class PricingModule {} diff --git a/src/payment/models/pricing/services/dfi-pricing-dex.service.ts b/src/payment/models/pricing/services/dfi-pricing-dex.service.ts new file mode 100644 index 0000000000..9b09c3b911 --- /dev/null +++ b/src/payment/models/pricing/services/dfi-pricing-dex.service.ts @@ -0,0 +1,43 @@ +import { v4 as uuid } from 'uuid'; +import { Injectable } from '@nestjs/common'; +import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; +import { AssetService } from 'src/shared/models/asset/asset.service'; +import { LiquidityOrderContext } from '../../dex/entities/liquidity-order.entity'; +import { LiquidityRequest } from '../../dex/interfaces'; +import { DexService } from '../../dex/services/dex.service'; +import { Price } from '../../exchange/dto/price.dto'; +import { PriceProvider } from '../interfaces'; +import { Util } from 'src/shared/util'; + +@Injectable() +export class DfiPricingDexService implements PriceProvider { + name: string; + + constructor(private dexService: DexService, private assetService: AssetService) { + this.name = 'DfiDex'; + } + + async getPrice(from: string, to: string): Promise { + if (to !== 'DFI') { + throw new Error(`DfiPricingDexService supports only DFI as target asset, instead provided: ${to}`); + } + + const dfi = await this.assetService.getAssetByQuery({ dexName: 'DFI', blockchain: Blockchain.DEFICHAIN }); + + const liquidityRequest: LiquidityRequest = { + context: LiquidityOrderContext.PRICING, + correlationId: uuid(), + referenceAsset: from, + referenceAmount: 1, + targetAsset: dfi, + options: { + bypassAvailabilityCheck: true, + bypassSlippageProtection: true, + }, + }; + + const targetAmount = await this.dexService.checkLiquidity(liquidityRequest); + + return Price.create(from, to, Util.round(targetAmount, 8)); + } +} diff --git a/src/payment/models/pricing/services/pricing.service.ts b/src/payment/models/pricing/services/pricing.service.ts index 8d01772a31..88666036cc 100644 --- a/src/payment/models/pricing/services/pricing.service.ts +++ b/src/payment/models/pricing/services/pricing.service.ts @@ -14,6 +14,7 @@ import { PathNotConfiguredException } from '../exceptions/path-not-configured.ex import { PriceRequest, PriceResult } from '../interfaces'; import { PricePath } from '../utils/price-path'; import { PriceStep } from '../utils/price-step'; +import { DfiPricingDexService } from './dfi-pricing-dex.service'; export enum PricingPathAlias { MATCHING_ASSETS = 'MatchingAssets', @@ -25,7 +26,7 @@ export enum PricingPathAlias { MATCHING_FIAT_TO_USD_STABLE_COIN = 'MatchingFiatToUSDStableCoin', NON_MATCHING_FIAT_TO_USD_STABLE_COIN = 'NonMatchingFiatToUSDStableCoin', NON_MATCHING_USD_STABLE_COIN_TO_USD_STABLE_COIN = 'NonMatchingUSDStableCoinToUSDStableCoin', - // TODO -DFI case separately through testPoolSwap -> DEX + FIAT_TO_DFI = 'FiatToDfi', } @Injectable() @@ -41,6 +42,7 @@ export class PricingService { private readonly ftxService: FtxService, private readonly currencyService: CurrencyService, private readonly fixerService: FixerService, + private readonly dfiDexService: DfiPricingDexService, ) { this.configurePaths(); } @@ -183,6 +185,25 @@ export class PricingService { }), ]), ); + + this.addPath( + new PricePath(PricingPathAlias.FIAT_TO_DFI, [ + new PriceStep({ + to: 'BTC', + providers: { + primary: [this.krakenService], + reference: [this.binanceService, this.bitstampService, this.bitpandaService], + }, + }), + new PriceStep({ + from: 'BTC', + providers: { + primary: [this.dfiDexService], + reference: [], + }, + }), + ]), + ); } //*** HELPER METHODS ***// @@ -231,6 +252,8 @@ export class PricingService { return PricingPathAlias.NON_MATCHING_USD_STABLE_COIN_TO_USD_STABLE_COIN; } + if (this.isFiat(from) && to === 'DFI') return PricingPathAlias.FIAT_TO_DFI; + throw new Error(`No matching pricing path alias found. From: ${request.from} to: ${request.to}`); } @@ -251,7 +274,9 @@ export class PricingService { } private isKnownAsset(asset: string): boolean { - return this.isFiat(asset) || this.isBTC(asset) || this.isAltcoin(asset) || this.isUSDStablecoin(asset); + return ( + this.isFiat(asset) || this.isBTC(asset) || this.isAltcoin(asset) || this.isUSDStablecoin(asset) || asset === 'DFI' + ); } private logPriceResult(request: PriceRequest, result: PriceResult, pathAlias: PricingPathAlias): void { From 074a0bc70e2dd07ab06e843874dcfcd22033e3a9 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Thu, 6 Oct 2022 15:23:34 +0200 Subject: [PATCH 16/30] [DEV-622] refactored bitcoin payout strategy to use shared jellyfish functionality --- .../services/base/payout-jellyfish.service.ts | 8 ++++ .../payout/services/payout-bitcoin.service.ts | 9 ++-- .../services/payout-defichain.service.ts | 6 +-- ...c.ts => payout-jellyfish.strategy.spec.ts} | 14 +++--- .../payout/__tests__/payout.facade.spec.ts | 2 +- ...hain.strategy.ts => jellyfish.strategy.ts} | 21 ++++----- .../payout/impl/bitcoin.strategy.ts | 44 +++++++++++++++---- .../payout/impl/defichain-dfi.strategy.ts | 17 ++++--- .../payout/impl/defichain-token.strategy.ts | 21 +++++---- 9 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 src/payment/models/payout/services/base/payout-jellyfish.service.ts rename src/payment/models/payout/strategies/payout/__tests__/{payout-defichain.strategy.spec.ts => payout-jellyfish.strategy.spec.ts} (96%) rename src/payment/models/payout/strategies/payout/impl/base/{defichain.strategy.ts => jellyfish.strategy.ts} (87%) diff --git a/src/payment/models/payout/services/base/payout-jellyfish.service.ts b/src/payment/models/payout/services/base/payout-jellyfish.service.ts new file mode 100644 index 0000000000..fdeccbba7f --- /dev/null +++ b/src/payment/models/payout/services/base/payout-jellyfish.service.ts @@ -0,0 +1,8 @@ +import { PayoutOrderContext } from '../../entities/payout-order.entity'; + +export type PayoutGroup = { addressTo: string; amount: number }[]; + +export abstract class PayoutJellyfishService { + abstract isHealthy(context: PayoutOrderContext): Promise; + abstract checkPayoutCompletion(context: PayoutOrderContext, payoutTxId: string): Promise; +} diff --git a/src/payment/models/payout/services/payout-bitcoin.service.ts b/src/payment/models/payout/services/payout-bitcoin.service.ts index cc5e73462e..c855b2d145 100644 --- a/src/payment/models/payout/services/payout-bitcoin.service.ts +++ b/src/payment/models/payout/services/payout-bitcoin.service.ts @@ -1,14 +1,15 @@ import { Injectable } from '@nestjs/common'; import { BtcClient } from 'src/blockchain/ain/node/btc-client'; import { NodeService, NodeType } from 'src/blockchain/ain/node/node.service'; - -export type PayoutGroup = { addressTo: string; amount: number }[]; +import { PayoutOrderContext } from '../entities/payout-order.entity'; +import { PayoutGroup, PayoutJellyfishService } from './base/payout-jellyfish.service'; @Injectable() -export class PayoutBitcoinService { +export class PayoutBitcoinService extends PayoutJellyfishService { #client: BtcClient; constructor(readonly nodeService: NodeService) { + super(); nodeService.getConnectedNode(NodeType.BTC_OUTPUT).subscribe((client) => (this.#client = client)); } @@ -20,7 +21,7 @@ export class PayoutBitcoinService { } } - async sendUtxoToMany(payout: PayoutGroup): Promise { + async sendUtxoToMany(_context: PayoutOrderContext, payout: PayoutGroup): Promise { return this.#client.sendUtxoToMany(payout); } diff --git a/src/payment/models/payout/services/payout-defichain.service.ts b/src/payment/models/payout/services/payout-defichain.service.ts index da63652b2e..5ca921d94d 100644 --- a/src/payment/models/payout/services/payout-defichain.service.ts +++ b/src/payment/models/payout/services/payout-defichain.service.ts @@ -4,15 +4,15 @@ import { NodeService, NodeType } from 'src/blockchain/ain/node/node.service'; import { WhaleService } from 'src/blockchain/ain/whale/whale.service'; import { Config } from 'src/config/config'; import { PayoutOrderContext } from '../entities/payout-order.entity'; - -export type PayoutGroup = { addressTo: string; amount: number }[]; +import { PayoutGroup, PayoutJellyfishService } from './base/payout-jellyfish.service'; @Injectable() -export class PayoutDeFiChainService { +export class PayoutDeFiChainService extends PayoutJellyfishService { #outClient: DeFiClient; #intClient: DeFiClient; constructor(readonly nodeService: NodeService, private readonly whaleService: WhaleService) { + super(); nodeService.getConnectedNode(NodeType.OUTPUT).subscribe((client) => (this.#outClient = client)); nodeService.getConnectedNode(NodeType.INT).subscribe((client) => (this.#intClient = client)); } diff --git a/src/payment/models/payout/strategies/payout/__tests__/payout-defichain.strategy.spec.ts b/src/payment/models/payout/strategies/payout/__tests__/payout-jellyfish.strategy.spec.ts similarity index 96% rename from src/payment/models/payout/strategies/payout/__tests__/payout-defichain.strategy.spec.ts rename to src/payment/models/payout/strategies/payout/__tests__/payout-jellyfish.strategy.spec.ts index 1846170b73..b8868b2337 100644 --- a/src/payment/models/payout/strategies/payout/__tests__/payout-defichain.strategy.spec.ts +++ b/src/payment/models/payout/strategies/payout/__tests__/payout-jellyfish.strategy.spec.ts @@ -8,10 +8,10 @@ import { } from '../../../entities/__mocks__/payout-order.entity.mock'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; -import { DeFiChainStrategy } from '../impl/base/defichain.strategy'; +import { JellyfishStrategy } from '../impl/base/jellyfish.strategy'; -describe('PayoutDeFiChainStrategy', () => { - let strategy: PayoutDeFiChainStrategyWrapper; +describe('PayoutJellyfishStrategy', () => { + let strategy: PayoutJellyfishStrategyWrapper; let mailService: MailService; let payoutOrderRepo: PayoutOrderRepository; @@ -28,7 +28,7 @@ describe('PayoutDeFiChainStrategy', () => { repoSaveSpy = jest.spyOn(payoutOrderRepo, 'save'); sendErrorMailSpy = jest.spyOn(mailService, 'sendErrorMail'); - strategy = new PayoutDeFiChainStrategyWrapper(mailService, payoutOrderRepo, defichainService); + strategy = new PayoutJellyfishStrategyWrapper(mailService, payoutOrderRepo, defichainService); }); afterEach(() => { @@ -250,7 +250,7 @@ describe('PayoutDeFiChainStrategy', () => { }); }); -class PayoutDeFiChainStrategyWrapper extends DeFiChainStrategy { +class PayoutJellyfishStrategyWrapper extends JellyfishStrategy { constructor( mailService: MailService, payoutOrderRepo: PayoutOrderRepository, @@ -263,6 +263,10 @@ class PayoutDeFiChainStrategyWrapper extends DeFiChainStrategy { throw new Error('Method not implemented.'); } + protected async dispatchPayout(): Promise { + return 'TX_ID_01'; + } + groupOrdersByContextWrapper(orders: PayoutOrder[]) { return this.groupOrdersByContext(orders); } diff --git a/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts b/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts index 4820e80210..dc81c13499 100644 --- a/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts +++ b/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts @@ -30,7 +30,7 @@ describe('PayoutStrategiesFacade', () => { let facade: PayoutStrategiesFacadeWrapper; beforeEach(() => { - bitcoin = new BitcoinStrategy(mock(), mock()); + bitcoin = new BitcoinStrategy(mock(), mock(), mock()); deFiChainDfi = new DeFiChainDfiStrategy( mock(), mock(), diff --git a/src/payment/models/payout/strategies/payout/impl/base/defichain.strategy.ts b/src/payment/models/payout/strategies/payout/impl/base/jellyfish.strategy.ts similarity index 87% rename from src/payment/models/payout/strategies/payout/impl/base/defichain.strategy.ts rename to src/payment/models/payout/strategies/payout/impl/base/jellyfish.strategy.ts index 90698b8f4f..7f2c58902a 100644 --- a/src/payment/models/payout/strategies/payout/impl/base/defichain.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/base/jellyfish.strategy.ts @@ -1,15 +1,15 @@ +import { PayoutGroup, PayoutJellyfishService } from 'src/payment/models/payout/services/base/payout-jellyfish.service'; import { MailService } from 'src/shared/services/mail.service'; import { Util } from 'src/shared/util'; import { PayoutOrder, PayoutOrderContext } from '../../../../entities/payout-order.entity'; import { PayoutOrderRepository } from '../../../../repositories/payout-order.repository'; -import { PayoutDeFiChainService, PayoutGroup } from '../../../../services/payout-defichain.service'; import { PayoutStrategy } from './payout.strategy'; -export abstract class DeFiChainStrategy implements PayoutStrategy { +export abstract class JellyfishStrategy implements PayoutStrategy { constructor( protected readonly mailService: MailService, protected readonly payoutOrderRepo: PayoutOrderRepository, - protected readonly defichainService: PayoutDeFiChainService, + protected readonly jellyfishService: PayoutJellyfishService, ) {} async doPayout(orders: PayoutOrder[]): Promise { @@ -17,7 +17,7 @@ export abstract class DeFiChainStrategy implements PayoutStrategy { const groups = this.groupOrdersByContext(orders); for (const [context, group] of [...groups.entries()]) { - if (!(await this.defichainService.isHealthy(context))) return; + if (!(await this.jellyfishService.isHealthy(context))) return; await this.doPayoutForContext(context, group); } @@ -28,7 +28,7 @@ export abstract class DeFiChainStrategy implements PayoutStrategy { async checkPayoutCompletion(order: PayoutOrder): Promise { try { - const isComplete = await this.defichainService.checkPayoutCompletion(order.context, order.payoutTxId); + const isComplete = await this.jellyfishService.checkPayoutCompletion(order.context, order.payoutTxId); if (isComplete) { order.complete(); @@ -80,19 +80,20 @@ export abstract class DeFiChainStrategy implements PayoutStrategy { return [...result.values()]; } - protected async send( + protected abstract dispatchPayout( context: PayoutOrderContext, - orders: PayoutOrder[], + payout: PayoutGroup, outputAsset: string, - dispatcher: (context: PayoutOrderContext, payout: PayoutGroup, outputAsset: string) => Promise, - ): Promise { + ): Promise; + + protected async send(context: PayoutOrderContext, orders: PayoutOrder[], outputAsset: string): Promise { let payoutTxId: string; try { const payout = this.aggregatePayout(orders); await this.designatePayout(orders); - payoutTxId = await dispatcher(context, payout, outputAsset); + payoutTxId = await this.dispatchPayout(context, payout, outputAsset); } catch (e) { console.error(`Error on sending ${outputAsset} for payout. Order ID(s): ${orders.map((o) => o.id)}`, e); diff --git a/src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts b/src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts index 17563d20a4..c19d7eadb4 100644 --- a/src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts @@ -1,21 +1,49 @@ import { Injectable } from '@nestjs/common'; -import { PayoutOrder } from '../../../entities/payout-order.entity'; +import { MailService } from 'src/shared/services/mail.service'; +import { PayoutOrder, PayoutOrderContext } from '../../../entities/payout-order.entity'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutGroup } from '../../../services/base/payout-jellyfish.service'; import { PayoutBitcoinService } from '../../../services/payout-bitcoin.service'; -import { PayoutStrategy } from './base/payout.strategy'; +import { JellyfishStrategy } from './base/jellyfish.strategy'; @Injectable() -export class BitcoinStrategy implements PayoutStrategy { +export class BitcoinStrategy extends JellyfishStrategy { constructor( + mailService: MailService, protected readonly bitcoinService: PayoutBitcoinService, protected readonly payoutOrderRepo: PayoutOrderRepository, - ) {} + ) { + super(mailService, payoutOrderRepo, bitcoinService); + this.bitcoinService.sendUtxoToMany = this.bitcoinService.sendUtxoToMany.bind(this.bitcoinService); + } + + protected async doPayoutForContext(context: PayoutOrderContext, orders: PayoutOrder[]): Promise { + const payoutGroups = this.createPayoutGroups(orders, 100); + + for (const group of payoutGroups) { + try { + if (group.length === 0) { + continue; + } + + console.info(`Paying out ${group.length} BTC orders(s). Order ID(s): ${group.map((o) => o.id)}`); + + await this.sendBTC(context, group); + } catch (e) { + console.error( + `Error in paying out a group of ${group.length} BTC orders(s). Order ID(s): ${group.map((o) => o.id)}`, + ); + // continue with next group in case payout failed + continue; + } + } + } - doPayout(orders: PayoutOrder[]): Promise { - throw new Error('Method not implemented.'); + protected dispatchPayout(context: PayoutOrderContext, payout: PayoutGroup): Promise { + return this.bitcoinService.sendUtxoToMany(context, payout); } - checkPayoutCompletion(order: PayoutOrder): Promise { - throw new Error('Method not implemented.'); + private async sendBTC(context: PayoutOrderContext, orders: PayoutOrder[]): Promise { + await this.send(context, orders, 'BTC'); } } diff --git a/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts b/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts index b6201a1042..dd935332ab 100644 --- a/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts @@ -2,18 +2,19 @@ import { Injectable } from '@nestjs/common'; import { MailService } from 'src/shared/services/mail.service'; import { PayoutOrderContext, PayoutOrder } from '../../../entities/payout-order.entity'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutGroup } from '../../../services/base/payout-jellyfish.service'; import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; -import { DeFiChainStrategy } from './base/defichain.strategy'; +import { JellyfishStrategy } from './base/jellyfish.strategy'; @Injectable() -export class DeFiChainDfiStrategy extends DeFiChainStrategy { +export class DeFiChainDfiStrategy extends JellyfishStrategy { constructor( mailService: MailService, - protected readonly defichainService: PayoutDeFiChainService, + protected readonly jellyfishService: PayoutDeFiChainService, protected readonly payoutOrderRepo: PayoutOrderRepository, ) { - super(mailService, payoutOrderRepo, defichainService); - this.defichainService.sendUtxoToMany = this.defichainService.sendUtxoToMany.bind(this.defichainService); + super(mailService, payoutOrderRepo, jellyfishService); + this.jellyfishService.sendUtxoToMany = this.jellyfishService.sendUtxoToMany.bind(this.jellyfishService); } protected async doPayoutForContext(context: PayoutOrderContext, orders: PayoutOrder[]): Promise { @@ -38,7 +39,11 @@ export class DeFiChainDfiStrategy extends DeFiChainStrategy { } } + protected dispatchPayout(context: PayoutOrderContext, payout: PayoutGroup): Promise { + return this.jellyfishService.sendUtxoToMany(context, payout); + } + private async sendDFI(context: PayoutOrderContext, orders: PayoutOrder[]): Promise { - await this.send(context, orders, 'DFI', this.defichainService.sendUtxoToMany); + await this.send(context, orders, 'DFI'); } } diff --git a/src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts b/src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts index 2e302d1842..5afd61916f 100644 --- a/src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts @@ -3,21 +3,22 @@ import { DexService } from 'src/payment/models/dex/services/dex.service'; import { MailService } from 'src/shared/services/mail.service'; import { PayoutOrderContext, PayoutOrder } from '../../../entities/payout-order.entity'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; +import { PayoutGroup } from '../../../services/base/payout-jellyfish.service'; import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; -import { DeFiChainStrategy } from './base/defichain.strategy'; +import { JellyfishStrategy } from './base/jellyfish.strategy'; type TokenName = string; @Injectable() -export class DeFiChainTokenStrategy extends DeFiChainStrategy { +export class DeFiChainTokenStrategy extends JellyfishStrategy { constructor( mailService: MailService, private readonly dexService: DexService, - protected readonly defichainService: PayoutDeFiChainService, + protected readonly jellyfishService: PayoutDeFiChainService, protected readonly payoutOrderRepo: PayoutOrderRepository, ) { - super(mailService, payoutOrderRepo, defichainService); - this.defichainService.sendTokenToMany = this.defichainService.sendTokenToMany.bind(this.defichainService); + super(mailService, payoutOrderRepo, jellyfishService); + this.jellyfishService.sendTokenToMany = this.jellyfishService.sendTokenToMany.bind(this.jellyfishService); } protected async doPayoutForContext(context: PayoutOrderContext, orders: PayoutOrder[]): Promise { @@ -72,18 +73,22 @@ export class DeFiChainTokenStrategy extends DeFiChainStrategy { } private isEligibleForMinimalUtxo(address: string): boolean { - return this.defichainService.isLightWalletAddress(address); + return this.jellyfishService.isLightWalletAddress(address); } private async checkUtxo(address: string): Promise { - const utxo = await this.defichainService.getUtxoForAddress(address); + const utxo = await this.jellyfishService.getUtxoForAddress(address); if (!utxo) { await this.dexService.transferMinimalUtxo(address); } } + protected dispatchPayout(context: PayoutOrderContext, payout: PayoutGroup, outputAsset: string): Promise { + return this.jellyfishService.sendTokenToMany(context, payout, outputAsset); + } + private async sendToken(context: PayoutOrderContext, orders: PayoutOrder[], outputAsset: string): Promise { - await this.send(context, orders, outputAsset, this.defichainService.sendTokenToMany); + await this.send(context, orders, outputAsset); } } From c8c3eec038b3a858c66a8c769fa349751b8c6aa3 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Thu, 6 Oct 2022 15:24:24 +0200 Subject: [PATCH 17/30] [DEV-622] remove redundant method binding --- .../models/payout/strategies/payout/impl/bitcoin.strategy.ts | 1 - .../payout/strategies/payout/impl/defichain-dfi.strategy.ts | 1 - .../payout/strategies/payout/impl/defichain-token.strategy.ts | 1 - 3 files changed, 3 deletions(-) diff --git a/src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts b/src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts index c19d7eadb4..2068094ca5 100644 --- a/src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/bitcoin.strategy.ts @@ -14,7 +14,6 @@ export class BitcoinStrategy extends JellyfishStrategy { protected readonly payoutOrderRepo: PayoutOrderRepository, ) { super(mailService, payoutOrderRepo, bitcoinService); - this.bitcoinService.sendUtxoToMany = this.bitcoinService.sendUtxoToMany.bind(this.bitcoinService); } protected async doPayoutForContext(context: PayoutOrderContext, orders: PayoutOrder[]): Promise { diff --git a/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts b/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts index dd935332ab..074ffa9d18 100644 --- a/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts @@ -14,7 +14,6 @@ export class DeFiChainDfiStrategy extends JellyfishStrategy { protected readonly payoutOrderRepo: PayoutOrderRepository, ) { super(mailService, payoutOrderRepo, jellyfishService); - this.jellyfishService.sendUtxoToMany = this.jellyfishService.sendUtxoToMany.bind(this.jellyfishService); } protected async doPayoutForContext(context: PayoutOrderContext, orders: PayoutOrder[]): Promise { diff --git a/src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts b/src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts index 5afd61916f..af93a5ffa9 100644 --- a/src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/defichain-token.strategy.ts @@ -18,7 +18,6 @@ export class DeFiChainTokenStrategy extends JellyfishStrategy { protected readonly payoutOrderRepo: PayoutOrderRepository, ) { super(mailService, payoutOrderRepo, jellyfishService); - this.jellyfishService.sendTokenToMany = this.jellyfishService.sendTokenToMany.bind(this.jellyfishService); } protected async doPayoutForContext(context: PayoutOrderContext, orders: PayoutOrder[]): Promise { From 815166c693f6fb736261f1c1236f83aadae24a89 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Thu, 6 Oct 2022 16:04:30 +0200 Subject: [PATCH 18/30] [DEV-622] implemented reference assets rules for evm liquidity strategies --- src/blockchain/shared/evm/evm-client.ts | 6 +-- .../models/dex/services/dex-evm.service.ts | 22 +++++++-- .../impl/base/evm-crypto.strategy.ts | 11 +++-- .../impl/base/evm-crypto.strategy.ts | 3 +- .../impl/base/evm-token.strategy.ts | 47 ++++--------------- 5 files changed, 39 insertions(+), 50 deletions(-) diff --git a/src/blockchain/shared/evm/evm-client.ts b/src/blockchain/shared/evm/evm-client.ts index 7c046d5ced..130a100410 100644 --- a/src/blockchain/shared/evm/evm-client.ts +++ b/src/blockchain/shared/evm/evm-client.ts @@ -58,9 +58,9 @@ export class EvmClient { return this.#provider.getTransaction(txHash); } - async testSwap(tokenFrom: string, tokenTo: Asset, amount: number): Promise { - const inputAmount = ethers.utils.parseUnits(`${amount}`, 'ether'); - const outputAmounts = await this.#router.getAmountsOut(inputAmount, [tokenTo.chainId]); + async nativeCryptoTestSwap(nativeCryptoAmount: number, targetToken: Asset): Promise { + const inputAmount = ethers.utils.parseUnits(`${nativeCryptoAmount}`, 'ether'); + const outputAmounts = await this.#router.getAmountsOut(inputAmount, [targetToken.chainId]); return +ethers.utils.parseUnits(outputAmounts[0], 'wei'); } diff --git a/src/payment/models/dex/services/dex-evm.service.ts b/src/payment/models/dex/services/dex-evm.service.ts index d9009e3656..b23aa49887 100644 --- a/src/payment/models/dex/services/dex-evm.service.ts +++ b/src/payment/models/dex/services/dex-evm.service.ts @@ -19,7 +19,7 @@ export abstract class DexEvmService { this.#client = service.getDefaultClient(); } - async checkCoinAvailability(amount: number): Promise { + async checkNativeCryptoAvailability(amount: number): Promise { const pendingAmount = await this.getPendingAmount(this.nativeCoin); const availableAmount = await this.#client.getNativeCryptoBalance(); @@ -29,11 +29,11 @@ export abstract class DexEvmService { } async getAndCheckTokenAvailability(sourceAsset: string, sourceAmount: number, targetAsset: Asset): Promise { - const targetAmount = await this.#client.testSwap(sourceAsset, targetAsset, sourceAmount); + const amount = await this.getTargetAmount(sourceAsset, sourceAmount, targetAsset); - await this.checkAssetAvailability(targetAsset, targetAmount); + await this.checkTokenAvailability(targetAsset, amount); - return targetAmount; + return amount; } get _nativeCoin(): string { @@ -42,7 +42,19 @@ export abstract class DexEvmService { //*** HELPER METHODS ***// - private async checkAssetAvailability(asset: Asset, amount: number): Promise { + private async getTargetAmount(sourceAsset: string, sourceAmount: number, targetAsset: Asset): Promise { + if (sourceAsset === targetAsset.dexName) return sourceAmount; + if (sourceAsset !== this._nativeCoin) { + // only native coin is enabled as a sourceAsset + throw new Error( + `Only native coin reference is supported by EVM test swap. Provided source asset: ${sourceAsset}. Target asset: ${targetAsset.dexName}. Blockchain: ${targetAsset.blockchain}`, + ); + } + + return this.#client.nativeCryptoTestSwap(sourceAmount, targetAsset); + } + + private async checkTokenAvailability(asset: Asset, amount: number): Promise { const pendingAmount = await this.getPendingAmount(asset.dexName); const availableAmount = await this.#client.getTokenBalance(asset); diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-crypto.strategy.ts index 562e4302c6..7ae7ef9dd9 100644 --- a/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-crypto.strategy.ts @@ -6,10 +6,15 @@ export class EvmCryptoStrategy implements CheckLiquidityStrategy { constructor(protected readonly dexEvmService: DexEvmService) {} async checkLiquidity(request: LiquidityRequest): Promise { - const targetAmount = request.referenceAmount; + const { referenceAsset, referenceAmount, context, correlationId } = request; - await this.dexEvmService.checkCoinAvailability(targetAmount); + if (referenceAsset === this.dexEvmService._nativeCoin) { + return this.dexEvmService.checkNativeCryptoAvailability(referenceAmount); + } - return targetAmount; + // only native coin is enabled as a referenceAsset + throw new Error( + `Only native coin reference is supported by EVM CheckLiquidity strategy. Provided reference asset: ${referenceAsset} Context: ${context}. CorrelationID: ${correlationId}`, + ); } } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts index bf91d24c1b..4599342b2d 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts @@ -10,10 +10,11 @@ export class EvmCryptoStrategy extends PurchaseLiquidityStrategy { async purchaseLiquidity(request: LiquidityRequest): Promise { const { referenceAsset, referenceAmount, context, correlationId } = request; + try { // should always throw, even if there is amount, additional check is done for API consistency and sending mail if (referenceAsset === this.dexEvmService._nativeCoin) { - const amount = await this.dexEvmService.checkCoinAvailability(referenceAmount); + const amount = await this.dexEvmService.checkNativeCryptoAvailability(referenceAmount); if (amount) { throw new Error( diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts index 8d0c0e6870..77abb7bffd 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-token.strategy.ts @@ -13,48 +13,19 @@ export class EvmTokenStrategy extends PurchaseLiquidityStrategy { try { // should always throw, even if there is amount, additional check is done for API consistency and sending mail - if (referenceAsset === this.dexEvmService._nativeCoin) { - const amount = await this.dexEvmService.getAndCheckTokenAvailability( - referenceAsset, - referenceAmount, - targetAsset, - ); + const amount = await this.dexEvmService.getAndCheckTokenAvailability( + referenceAsset, + referenceAmount, + targetAsset, + ); - if (amount) { - throw new Error( - `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, - ); - } + if (amount) { + throw new Error( + `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, + ); } - - // throw by default, only native coin is enabled as a referenceAsset - throw new Error( - `Only native coin reference is supported by EVM PurchaseLiquidity strategy. Provided reference asset: ${referenceAsset} Context: ${context}. CorrelationID: ${correlationId}`, - ); } catch (e) { await this.handlePurchaseLiquidityError(e, request); } } } - -// const { referenceAsset, referenceAmount, context, correlationId } = request; -// try { -// // should always throw, even if there is amount, additional check is done for API consistency and sending mail -// if (referenceAsset === this.dexEvmService._nativeCoin) { -// const amount = await this.dexEvmService.checkCoinAvailability(referenceAmount); - -// if (amount) { -// throw new Error( -// `Requested ${referenceAsset} liquidity is already available on the wallet. No purchase required, retry checkLiquidity. Context: ${context}. CorrelationID: ${correlationId}`, -// ); -// } -// } - -// // throw by default, only native coin trading enabled -// throw new Error( -// `Only native coins are supported by EVM PurchaseLiquidity strategy. Provided reference asset: ${referenceAsset} Context: ${context}. CorrelationID: ${correlationId}`, -// ); -// } catch (e) { -// await this.handlePurchaseLiquidityError(e, request); -// } -// } From a9649c25f403641de9a92ccd22c50786ba477ea6 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Fri, 7 Oct 2022 09:51:51 +0200 Subject: [PATCH 19/30] [DEV-622] fixed abi import path --- src/blockchain/shared/evm/evm-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blockchain/shared/evm/evm-client.ts b/src/blockchain/shared/evm/evm-client.ts index 130a100410..6224b01f69 100644 --- a/src/blockchain/shared/evm/evm-client.ts +++ b/src/blockchain/shared/evm/evm-client.ts @@ -1,7 +1,7 @@ import { Contract, ethers } from 'ethers'; import { Asset } from 'src/shared/models/asset/asset.entity'; import * as ERC20_ABI from './abi/erc20.abi.json'; -import * as UNISWAP_ROUTER_02_ABI from './abi/erc20.abi.json'; +import * as UNISWAP_ROUTER_02_ABI from './abi/uniswap-router02.abi.json'; export class EvmClient { #dfxAddress: string; From 3cfcc1b58d99c1757fd784f0d65859c9ba5fe0c3 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Fri, 7 Oct 2022 10:48:14 +0200 Subject: [PATCH 20/30] [DEV-622] changed naming in dfi payout strategy --- .../payout/strategies/payout/impl/defichain-dfi.strategy.ts | 6 +++--- .../models/pricing/services/dfi-pricing-dex.service.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts b/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts index 074ffa9d18..e50357d11c 100644 --- a/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts @@ -10,10 +10,10 @@ import { JellyfishStrategy } from './base/jellyfish.strategy'; export class DeFiChainDfiStrategy extends JellyfishStrategy { constructor( mailService: MailService, - protected readonly jellyfishService: PayoutDeFiChainService, + protected readonly deFiChainService: PayoutDeFiChainService, protected readonly payoutOrderRepo: PayoutOrderRepository, ) { - super(mailService, payoutOrderRepo, jellyfishService); + super(mailService, payoutOrderRepo, deFiChainService); } protected async doPayoutForContext(context: PayoutOrderContext, orders: PayoutOrder[]): Promise { @@ -39,7 +39,7 @@ export class DeFiChainDfiStrategy extends JellyfishStrategy { } protected dispatchPayout(context: PayoutOrderContext, payout: PayoutGroup): Promise { - return this.jellyfishService.sendUtxoToMany(context, payout); + return this.deFiChainService.sendUtxoToMany(context, payout); } private async sendDFI(context: PayoutOrderContext, orders: PayoutOrder[]): Promise { diff --git a/src/payment/models/pricing/services/dfi-pricing-dex.service.ts b/src/payment/models/pricing/services/dfi-pricing-dex.service.ts index 9b09c3b911..75e8470ec3 100644 --- a/src/payment/models/pricing/services/dfi-pricing-dex.service.ts +++ b/src/payment/models/pricing/services/dfi-pricing-dex.service.ts @@ -28,7 +28,7 @@ export class DfiPricingDexService implements PriceProvider { context: LiquidityOrderContext.PRICING, correlationId: uuid(), referenceAsset: from, - referenceAmount: 1, + referenceAmount: 0.001, targetAsset: dfi, options: { bypassAvailabilityCheck: true, @@ -38,6 +38,6 @@ export class DfiPricingDexService implements PriceProvider { const targetAmount = await this.dexService.checkLiquidity(liquidityRequest); - return Price.create(from, to, Util.round(targetAmount, 8)); + return Price.create(from, to, Util.round(targetAmount / 0.001, 8)); } } From f0eed20040b186ed79ef2a27753d3854786143bd Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 10 Oct 2022 09:54:14 +0200 Subject: [PATCH 21/30] [DEV-622] several adjustments during testing --- src/blockchain/shared/evm/evm-client.ts | 21 ++++++++++++++----- .../models/dex/services/dex-evm.service.ts | 2 +- .../payout/impl/base/evm.strategy.ts | 4 +++- .../payout/impl/bsc-crypto.strategy.ts | 7 ++++++- .../payout/impl/bsc-token.strategy.ts | 7 ++++++- .../payout/impl/ethereum-crypto.strategy.ts | 7 ++++++- .../payout/impl/ethereum-token.strategy.ts | 7 ++++++- 7 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/blockchain/shared/evm/evm-client.ts b/src/blockchain/shared/evm/evm-client.ts index 6224b01f69..a6df2344cd 100644 --- a/src/blockchain/shared/evm/evm-client.ts +++ b/src/blockchain/shared/evm/evm-client.ts @@ -8,7 +8,7 @@ export class EvmClient { #provider: ethers.providers.JsonRpcProvider; #wallet: ethers.Wallet; #router: Contract; - #erc20Tokens: Map; + #erc20Tokens: Map = new Map(); constructor(gatewayUrl: string, privateKey: string, dfxAddress: string, swapContractAddress: string) { this.#provider = new ethers.providers.JsonRpcProvider(gatewayUrl); @@ -24,7 +24,11 @@ export class EvmClient { } async getTokenBalance(token: Asset): Promise { - return this.getERC20Contract(token.chainId).balanceOf(this.#dfxAddress); + const contract = this.getERC20Contract(token.chainId); + const balance = await contract.balanceOf(this.#dfxAddress); + const decimals = await contract.decimals(); + + return parseFloat(ethers.utils.formatUnits(balance, decimals)); } async sendNativeCrypto(address: string, amount: number): Promise { @@ -44,8 +48,12 @@ export class EvmClient { async sendToken(address: string, token: Asset, amount: number): Promise { const contract = this.getERC20Contract(token.chainId); + const decimals = await contract.decimals(); + const targetAmount = ethers.utils.parseUnits(`${amount}`, decimals); - return await contract.transfer(address, ethers.utils.parseUnits(`${amount}`, 'ether')); + const tx = await contract.transfer(address, targetAmount); + + return tx.hash; } async isTxComplete(txHash: string): Promise { @@ -60,9 +68,12 @@ export class EvmClient { async nativeCryptoTestSwap(nativeCryptoAmount: number, targetToken: Asset): Promise { const inputAmount = ethers.utils.parseUnits(`${nativeCryptoAmount}`, 'ether'); - const outputAmounts = await this.#router.getAmountsOut(inputAmount, [targetToken.chainId]); + const outputAmounts = await this.#router.getAmountsOut(inputAmount, [ + '0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6', + targetToken.chainId, + ]); - return +ethers.utils.parseUnits(outputAmounts[0], 'wei'); + return +ethers.utils.parseUnits(outputAmounts[1], 'wei'); } //*** HELPER METHODS ***// diff --git a/src/payment/models/dex/services/dex-evm.service.ts b/src/payment/models/dex/services/dex-evm.service.ts index b23aa49887..3bc692c461 100644 --- a/src/payment/models/dex/services/dex-evm.service.ts +++ b/src/payment/models/dex/services/dex-evm.service.ts @@ -78,7 +78,7 @@ export abstract class DexEvmService { // 5% cap for unexpected meantime swaps if (requiredAmount * 1.05 > availableAmount - pendingAmount) { throw new NotEnoughLiquidityException( - `Not enough liquidity of asset ${this.nativeCoin}. Trying to use ${requiredAmount} ${assetName} worth liquidity. Available amount: ${availableAmount}. Pending amount: ${pendingAmount}`, + `Not enough liquidity of asset ${assetName}. Trying to use ${requiredAmount} ${assetName} worth liquidity. Available amount: ${availableAmount}. Pending amount: ${pendingAmount}`, ); } } diff --git a/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts b/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts index 5e12108740..6484043554 100644 --- a/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts @@ -9,10 +9,12 @@ export abstract class EvmStrategy implements PayoutStrategy { protected readonly payoutOrderRepo: PayoutOrderRepository, ) {} + protected abstract dispatchPayout(order: PayoutOrder): Promise; + async doPayout(orders: PayoutOrder[]): Promise { for (const order of orders) { try { - const txId = await this.payoutEvmService.sendNativeCrypto(order.destinationAddress, order.amount); + const txId = await this.dispatchPayout(order); order.pendingPayout(txId); await this.payoutOrderRepo.save(order); diff --git a/src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts b/src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts index 4f4ad22fcd..45828fa2f4 100644 --- a/src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts @@ -1,11 +1,16 @@ import { Injectable } from '@nestjs/common'; +import { PayoutOrder } from '../../../entities/payout-order.entity'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; import { PayoutBscService } from '../../../services/payout-bsc.service'; import { EvmStrategy } from './base/evm.strategy'; @Injectable() export class BscCryptoStrategy extends EvmStrategy { - constructor(bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { + constructor(protected readonly bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { super(bscService, payoutOrderRepo); } + + protected dispatchPayout(order: PayoutOrder): Promise { + return this.bscService.sendNativeCrypto(order.destinationAddress, order.amount); + } } diff --git a/src/payment/models/payout/strategies/payout/impl/bsc-token.strategy.ts b/src/payment/models/payout/strategies/payout/impl/bsc-token.strategy.ts index 800f4ba111..a6e178f2af 100644 --- a/src/payment/models/payout/strategies/payout/impl/bsc-token.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/bsc-token.strategy.ts @@ -1,11 +1,16 @@ import { Injectable } from '@nestjs/common'; +import { PayoutOrder } from '../../../entities/payout-order.entity'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; import { PayoutBscService } from '../../../services/payout-bsc.service'; import { EvmStrategy } from './base/evm.strategy'; @Injectable() export class BscTokenStrategy extends EvmStrategy { - constructor(bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { + constructor(protected readonly bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { super(bscService, payoutOrderRepo); } + + protected dispatchPayout(order: PayoutOrder): Promise { + return this.bscService.sendToken(order.destinationAddress, order.asset, order.amount); + } } diff --git a/src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts b/src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts index 5d9d9b0582..f3734499ce 100644 --- a/src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts @@ -1,11 +1,16 @@ import { Injectable } from '@nestjs/common'; +import { PayoutOrder } from '../../../entities/payout-order.entity'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; import { PayoutEthereumService } from '../../../services/payout-ethereum.service'; import { EvmStrategy } from './base/evm.strategy'; @Injectable() export class EthereumCryptoStrategy extends EvmStrategy { - constructor(ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { + constructor(protected readonly ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { super(ethereumService, payoutOrderRepo); } + + protected dispatchPayout(order: PayoutOrder): Promise { + return this.ethereumService.sendNativeCrypto(order.destinationAddress, order.amount); + } } diff --git a/src/payment/models/payout/strategies/payout/impl/ethereum-token.strategy.ts b/src/payment/models/payout/strategies/payout/impl/ethereum-token.strategy.ts index eac63af65e..e26fbe01c6 100644 --- a/src/payment/models/payout/strategies/payout/impl/ethereum-token.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/ethereum-token.strategy.ts @@ -1,11 +1,16 @@ import { Injectable } from '@nestjs/common'; +import { PayoutOrder } from '../../../entities/payout-order.entity'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; import { PayoutEthereumService } from '../../../services/payout-ethereum.service'; import { EvmStrategy } from './base/evm.strategy'; @Injectable() export class EthereumTokenStrategy extends EvmStrategy { - constructor(ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { + constructor(protected readonly ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { super(ethereumService, payoutOrderRepo); } + + protected dispatchPayout(order: PayoutOrder): Promise { + return this.ethereumService.sendToken(order.destinationAddress, order.asset, order.amount); + } } From c7159ff34d4710986d0de827a4ce9887ff068f74 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 10 Oct 2022 09:59:21 +0200 Subject: [PATCH 22/30] [DEV-622] fix payout completion check error --- .../models/payout/strategies/payout/impl/base/evm.strategy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts b/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts index 6484043554..db52b51f90 100644 --- a/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/base/evm.strategy.ts @@ -26,7 +26,7 @@ export abstract class EvmStrategy implements PayoutStrategy { async checkPayoutCompletion(order: PayoutOrder): Promise { try { - const isComplete = this.payoutEvmService.checkPayoutCompletion(order.payoutTxId); + const isComplete = await this.payoutEvmService.checkPayoutCompletion(order.payoutTxId); if (isComplete) { order.complete(); From b57e8df5e10d87287e750862ac5dde8e54484e14 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 10 Oct 2022 14:00:07 +0200 Subject: [PATCH 23/30] [DEV-622] made swap contract and token configurable --- src/blockchain/bsc/bsc.service.ts | 5 +++-- src/blockchain/ethereum/ethereum.service.ts | 20 +++++++++++++++++--- src/blockchain/shared/evm/evm-client.ts | 21 ++++++++++++++------- src/blockchain/shared/evm/evm.service.ts | 17 +++++++++++++++-- src/config/config.ts | 6 ++++-- 5 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/blockchain/bsc/bsc.service.ts b/src/blockchain/bsc/bsc.service.ts index d7896fbbea..3a282c9f37 100644 --- a/src/blockchain/bsc/bsc.service.ts +++ b/src/blockchain/bsc/bsc.service.ts @@ -6,8 +6,9 @@ import { EvmService } from '../shared/evm/evm.service'; @Injectable() export class BscService extends EvmService { constructor() { - const { bscGatewayUrl, bscWalletAddress, bscWalletPrivateKey, pancakeRouterAddress } = GetConfig().blockchain.bsc; + const { bscGatewayUrl, bscWalletAddress, bscWalletPrivateKey, pancakeRouterAddress, swapTokenAddress } = + GetConfig().blockchain.bsc; - super(bscGatewayUrl, '', bscWalletAddress, bscWalletPrivateKey, pancakeRouterAddress, BscClient); + super(bscGatewayUrl, '', bscWalletAddress, bscWalletPrivateKey, pancakeRouterAddress, swapTokenAddress, BscClient); } } diff --git a/src/blockchain/ethereum/ethereum.service.ts b/src/blockchain/ethereum/ethereum.service.ts index cf2d41f231..45b0669840 100644 --- a/src/blockchain/ethereum/ethereum.service.ts +++ b/src/blockchain/ethereum/ethereum.service.ts @@ -6,9 +6,23 @@ import { EvmService } from '../shared/evm/evm.service'; @Injectable() export class EthereumService extends EvmService { constructor() { - const { ethGatewayUrl, ethApiKey, ethWalletAddress, ethWalletPrivateKey, uniswapV2Router02Address } = - GetConfig().blockchain.ethereum; + const { + ethGatewayUrl, + ethApiKey, + ethWalletAddress, + ethWalletPrivateKey, + uniswapV2Router02Address, + swapTokenAddress, + } = GetConfig().blockchain.ethereum; - super(ethGatewayUrl, ethApiKey, ethWalletAddress, ethWalletPrivateKey, uniswapV2Router02Address, EthereumClient); + super( + ethGatewayUrl, + ethApiKey, + ethWalletAddress, + ethWalletPrivateKey, + uniswapV2Router02Address, + swapTokenAddress, + EthereumClient, + ); } } diff --git a/src/blockchain/shared/evm/evm-client.ts b/src/blockchain/shared/evm/evm-client.ts index a6df2344cd..6cdd9fe245 100644 --- a/src/blockchain/shared/evm/evm-client.ts +++ b/src/blockchain/shared/evm/evm-client.ts @@ -9,11 +9,19 @@ export class EvmClient { #wallet: ethers.Wallet; #router: Contract; #erc20Tokens: Map = new Map(); - - constructor(gatewayUrl: string, privateKey: string, dfxAddress: string, swapContractAddress: string) { + #swapTokenAddress: string; + + constructor( + gatewayUrl: string, + privateKey: string, + dfxAddress: string, + swapContractAddress: string, + swapTokenAddress: string, + ) { this.#provider = new ethers.providers.JsonRpcProvider(gatewayUrl); this.#wallet = new ethers.Wallet(privateKey, this.#provider); this.#dfxAddress = dfxAddress; + this.#swapTokenAddress = swapTokenAddress; this.#router = new ethers.Contract(swapContractAddress, UNISWAP_ROUTER_02_ABI, this.#wallet); } @@ -67,13 +75,12 @@ export class EvmClient { } async nativeCryptoTestSwap(nativeCryptoAmount: number, targetToken: Asset): Promise { + const contract = new ethers.Contract(targetToken.chainId, ERC20_ABI, this.#wallet); const inputAmount = ethers.utils.parseUnits(`${nativeCryptoAmount}`, 'ether'); - const outputAmounts = await this.#router.getAmountsOut(inputAmount, [ - '0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6', - targetToken.chainId, - ]); + const outputAmounts = await this.#router.getAmountsOut(inputAmount, [this.#swapTokenAddress, targetToken.chainId]); + const decimals = await contract.decimals(); - return +ethers.utils.parseUnits(outputAmounts[1], 'wei'); + return parseFloat(ethers.utils.formatUnits(outputAmounts[1], decimals)); } //*** HELPER METHODS ***// diff --git a/src/blockchain/shared/evm/evm.service.ts b/src/blockchain/shared/evm/evm.service.ts index 92c182098b..ce2fb20d70 100644 --- a/src/blockchain/shared/evm/evm.service.ts +++ b/src/blockchain/shared/evm/evm.service.ts @@ -9,11 +9,24 @@ export abstract class EvmService { walletAddress: string, walletPrivateKey: string, swapContractAddress: string, + swapTokenAddress: string, client: { - new (gatewayUrl: string, privateKey: string, dfxAddress: string, swapContractAddress: string): EvmClient; + new ( + gatewayUrl: string, + privateKey: string, + dfxAddress: string, + swapContractAddress: string, + swapTokenAddress: string, + ): EvmClient; }, ) { - this.client = new client(`${gatewayUrl}/${apiKey}`, walletPrivateKey, walletAddress, swapContractAddress); + this.client = new client( + `${gatewayUrl}/${apiKey}`, + walletPrivateKey, + walletAddress, + swapContractAddress, + swapTokenAddress, + ); } getDefaultClient(): T { diff --git a/src/config/config.ts b/src/config/config.ts index 358adc6f1f..e6811f34fb 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -216,13 +216,15 @@ export class Configuration { ethWalletPrivateKey: process.env.ETH_WALLET_PRIVATE_KEY, ethGatewayUrl: process.env.ETH_GATEWAY_URL, ethApiKey: process.env.ETH_API_KEY, - uniswapV2Router02Address: '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', + uniswapV2Router02Address: process.env.ETH_SWAP_CONTRACT_ADDRESS, + swapTokenAddress: process.env.ETH_SWAP_TOKEN_ADDRESS, }, bsc: { bscWalletAddress: process.env.BSC_WALLET_ADDRESS, bscWalletPrivateKey: process.env.BSC_WALLET_PRIVATE_KEY, bscGatewayUrl: process.env.BSC_GATEWAY_URL, - pancakeRouterAddress: '0x10ED43C718714eb63d5aA57B78B54704E256024E', + pancakeRouterAddress: process.env.BSC_SWAP_CONTRACT_ADDRESS, + swapTokenAddress: process.env.BSC_SWAP_TOKEN_ADDRESS, }, }; From e2b8118890e84f08ceb7659928611bd4b5d2e7af Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 10 Oct 2022 14:13:57 +0200 Subject: [PATCH 24/30] [DEV-622] fixed evm client construction --- src/blockchain/bsc/bsc-client.ts | 10 ++++++++-- src/blockchain/ethereum/ethereum-client.ts | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/blockchain/bsc/bsc-client.ts b/src/blockchain/bsc/bsc-client.ts index 0c73377070..98d4559b88 100644 --- a/src/blockchain/bsc/bsc-client.ts +++ b/src/blockchain/bsc/bsc-client.ts @@ -1,7 +1,13 @@ import { EvmClient } from '../shared/evm/evm-client'; export class BscClient extends EvmClient { - constructor(gatewayUrl: string, privateKey: string, dfxAddress: string, swapContractAddress: string) { - super(gatewayUrl, privateKey, dfxAddress, swapContractAddress); + constructor( + gatewayUrl: string, + privateKey: string, + dfxAddress: string, + swapContractAddress: string, + swapTokenAddress: string, + ) { + super(gatewayUrl, privateKey, dfxAddress, swapContractAddress, swapTokenAddress); } } diff --git a/src/blockchain/ethereum/ethereum-client.ts b/src/blockchain/ethereum/ethereum-client.ts index 3774ba6547..4bcf9228e0 100644 --- a/src/blockchain/ethereum/ethereum-client.ts +++ b/src/blockchain/ethereum/ethereum-client.ts @@ -1,7 +1,13 @@ import { EvmClient } from '../shared/evm/evm-client'; export class EthereumClient extends EvmClient { - constructor(gatewayUrl: string, privateKey: string, dfxAddress: string, swapContractAddress: string) { - super(gatewayUrl, privateKey, dfxAddress, swapContractAddress); + constructor( + gatewayUrl: string, + privateKey: string, + dfxAddress: string, + swapContractAddress: string, + swapTokenAddress: string, + ) { + super(gatewayUrl, privateKey, dfxAddress, swapContractAddress, swapTokenAddress); } } From 5624a942d90af1739d0a7227d46d1d0ba8801d63 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 10 Oct 2022 15:15:35 +0200 Subject: [PATCH 25/30] [DEV-622] extended env example file --- .env.example | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.env.example b/.env.example index 4f4202e873..d0cc361a06 100644 --- a/.env.example +++ b/.env.example @@ -36,9 +36,13 @@ ETH_WALLET_ADDRESS= ETH_WALLET_PRIVATE_KEY= ETH_GATEWAY_URL= ETH_API_KEY= +ETH_SWAP_CONTRACT_ADDRESS= +ETH_SWAP_TOKEN_ADDRESS= BSC_WALLET_ADDRESS= BSC_WALLET_PRIVATE_KEY= BSC_GATEWAY_URL= +BSC_SWAP_CONTRACT_ADDRESS= +BSC_SWAP_TOKEN_ADDRESS= LETTER_USER= LETTER_AUTH= LETTER_URL= From 1793df652cc56b9a51573831c34f6e1932fc5d4a Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 10 Oct 2022 15:23:39 +0200 Subject: [PATCH 26/30] [DEV-622] created migration --- migration/1665408086368-assetChainId.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 migration/1665408086368-assetChainId.js diff --git a/migration/1665408086368-assetChainId.js b/migration/1665408086368-assetChainId.js new file mode 100644 index 0000000000..97fddc4266 --- /dev/null +++ b/migration/1665408086368-assetChainId.js @@ -0,0 +1,15 @@ +const { MigrationInterface, QueryRunner } = require("typeorm"); + +module.exports = class assetChainId1665408086368 { + name = 'assetChainId1665408086368' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "asset" DROP COLUMN "chainId"`); + await queryRunner.query(`ALTER TABLE "asset" ADD "chainId" nvarchar(255)`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "asset" DROP COLUMN "chainId"`); + await queryRunner.query(`ALTER TABLE "asset" ADD "chainId" int`); + } +} From 71d847e8d99bb63c8fb69b21772e1ca684df26fb Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Mon, 10 Oct 2022 16:47:32 +0200 Subject: [PATCH 27/30] [DEV-622] implemented fallback to currency logic in pricing module --- .../__tests__/pricing.integration.spec.ts | 35 ++++++++++++++++++ .../pricing/services/pricing.service.ts | 19 +++++++++- .../utils/__mocks__/price-step.mock.ts | 2 +- .../models/pricing/utils/price-path.ts | 13 +++---- .../models/pricing/utils/price-step.ts | 36 +++++++++++++------ 5 files changed, 85 insertions(+), 20 deletions(-) diff --git a/src/payment/models/pricing/__tests__/pricing.integration.spec.ts b/src/payment/models/pricing/__tests__/pricing.integration.spec.ts index 3de0adec2f..279b38090a 100644 --- a/src/payment/models/pricing/__tests__/pricing.integration.spec.ts +++ b/src/payment/models/pricing/__tests__/pricing.integration.spec.ts @@ -313,6 +313,41 @@ describe('Pricing Module Integration Tests', () => { expect(result.path[0].timestamp).toBeInstanceOf(Date); }); + it('calculates price path for NON_MATCHING_FIAT_TO_BUSD', async () => { + krakenServiceGetPriceSpy = jest + .spyOn(krakenService, 'getPrice') + .mockImplementationOnce(async () => { + throw new Error(); + }) + .mockImplementationOnce(async (source, target) => createCustomPrice({ source, target, price: 1.1 })); + + fixerServiceGetPriceSpy = jest + .spyOn(fixerService, 'getPrice') + .mockImplementationOnce(async (source, target) => createCustomPrice({ source, target, price: 1.1 })); + + const request = { from: 'EUR', to: 'BUSD' }; + const result = await service.getPrice(request); + + expect(fixerServiceGetPriceSpy).toHaveBeenCalledWith('EUR', 'USD'); + + expect(result.price).toBeInstanceOf(Price); + expect(result.price.source).toBe('EUR'); + expect(result.price.target).toBe('BUSD'); + expect(result.price.price).toBe(1.1); + + expect(Array.isArray(result.path)).toBe(true); + expect(result.path.length).toBe(1); + + expect(result.path[0].provider).toBe('Kraken'); + + expect(result.path[0].price).toBeInstanceOf(Price); + expect(result.path[0].price.source).toBe('EUR'); + expect(result.path[0].price.target).toBe('USDC'); + expect(result.path[0].price.price).toBe(1.1); + + expect(result.path[0].timestamp).toBeInstanceOf(Date); + }); + it('calculates price path for NON_MATCHING_FIAT_TO_USD_STABLE_COIN', async () => { krakenServiceGetPriceSpy = jest .spyOn(krakenService, 'getPrice') diff --git a/src/payment/models/pricing/services/pricing.service.ts b/src/payment/models/pricing/services/pricing.service.ts index 88666036cc..c16577b603 100644 --- a/src/payment/models/pricing/services/pricing.service.ts +++ b/src/payment/models/pricing/services/pricing.service.ts @@ -24,6 +24,7 @@ export enum PricingPathAlias { ALTCOIN_TO_ALTCOIN = 'AltcoinToAltcoin', BTC_TO_ALTCOIN = 'BTCToAltcoin', MATCHING_FIAT_TO_USD_STABLE_COIN = 'MatchingFiatToUSDStableCoin', + NON_MATCHING_FIAT_TO_BUSD = 'NonMatchingFiatToBUSD', NON_MATCHING_FIAT_TO_USD_STABLE_COIN = 'NonMatchingFiatToUSDStableCoin', NON_MATCHING_USD_STABLE_COIN_TO_USD_STABLE_COIN = 'NonMatchingUSDStableCoinToUSDStableCoin', FIAT_TO_DFI = 'FiatToDfi', @@ -166,10 +167,23 @@ export class PricingService { ]), ); + this.addPath( + new PricePath(PricingPathAlias.NON_MATCHING_FIAT_TO_BUSD, [ + new PriceStep({ + overwriteReferenceTo: 'USD', + fallbackPrimaryTo: 'USDC', + providers: { + primary: [this.krakenService], + reference: [this.fixerService, this.currencyService], + }, + }), + ]), + ); + this.addPath( new PricePath(PricingPathAlias.NON_MATCHING_FIAT_TO_USD_STABLE_COIN, [ new PriceStep({ - referenceTo: 'USD', + overwriteReferenceTo: 'USD', providers: { primary: [this.krakenService], reference: [this.fixerService, this.currencyService], @@ -246,6 +260,9 @@ export class PricingService { if (from === 'USD' && this.isUSDStablecoin(to)) return PricingPathAlias.MATCHING_FIAT_TO_USD_STABLE_COIN; + if (this.isFiat(from) && this.isUSDStablecoin(to) && to === 'BUSD') + return PricingPathAlias.NON_MATCHING_FIAT_TO_BUSD; + if (this.isFiat(from) && this.isUSDStablecoin(to)) return PricingPathAlias.NON_MATCHING_FIAT_TO_USD_STABLE_COIN; if (this.isUSDStablecoin(from) && this.isUSDStablecoin(to) && from !== to) { diff --git a/src/payment/models/pricing/utils/__mocks__/price-step.mock.ts b/src/payment/models/pricing/utils/__mocks__/price-step.mock.ts index f10f90870e..43c5caa8a4 100644 --- a/src/payment/models/pricing/utils/__mocks__/price-step.mock.ts +++ b/src/payment/models/pricing/utils/__mocks__/price-step.mock.ts @@ -5,7 +5,7 @@ export function createDefaultPriceStep(): PriceStep { } export function createCustomPriceStep(customOptions: Partial): PriceStep { - const { from, to, referenceTo, providers, fixedPrice } = customOptions; + const { from, to, overwriteReferenceTo: referenceTo, providers, fixedPrice } = customOptions; const keys = Object.keys(customOptions); diff --git a/src/payment/models/pricing/utils/price-path.ts b/src/payment/models/pricing/utils/price-path.ts index e049bb801e..fc6566524f 100644 --- a/src/payment/models/pricing/utils/price-path.ts +++ b/src/payment/models/pricing/utils/price-path.ts @@ -34,26 +34,23 @@ export class PricePath { results.push(await step.execute()); } - return this.calculatePrice(results); + return this.calculatePrice(request, results); } //*** HELPER METHODS ***// - private calculatePrice(path: PriceStepResult[]): PriceResult { + private calculatePrice(request: PriceRequest, path: PriceStepResult[]): PriceResult { let result = 1; path.forEach((step) => { result = result * step.price.price; }); - return this.createPriceResult(path, result); + return this.createPriceResult(request, path, result); } - private createPriceResult(path: PriceStepResult[], targetPrice: number): PriceResult { - const firstStep = path[0]; - const lastStep = path[path.length - 1]; - - const price = Price.create(firstStep.price.source, lastStep.price.target, targetPrice); + private createPriceResult(request: PriceRequest, path: PriceStepResult[], targetPrice: number): PriceResult { + const price = Price.create(request.from, request.to, targetPrice); return { price, path }; } diff --git a/src/payment/models/pricing/utils/price-step.ts b/src/payment/models/pricing/utils/price-step.ts index fbdeb01291..af29b89ecc 100644 --- a/src/payment/models/pricing/utils/price-step.ts +++ b/src/payment/models/pricing/utils/price-step.ts @@ -7,7 +7,8 @@ import { PriceStepInitSpecification } from '../specifications/price-step-init.sp export interface PriceStepOptions { from?: string | 'input'; to?: string | 'output'; - referenceTo?: string; + overwriteReferenceTo?: string; + fallbackPrimaryTo?: string; providers?: PriceStepProviders; fixedPrice?: number; } @@ -24,7 +25,8 @@ export class PriceStep { this.options = { from: options.from || 'input', to: options.to || 'output', - referenceTo: options.referenceTo, + overwriteReferenceTo: options.overwriteReferenceTo, + fallbackPrimaryTo: options.fallbackPrimaryTo, providers: { primary: options.providers?.primary || [], reference: options.providers?.reference || [], @@ -102,14 +104,14 @@ export class PriceStep { private async getPrimaryPrice(fromCurrency: string, toCurrency: string): Promise<[Price, PriceProviderName]> { const primaryProviders = this.options.providers.primary; - const [price, providerName] = await this.tryProviders(fromCurrency, toCurrency, primaryProviders); + let [price, providerName] = await this.tryProviders(fromCurrency, toCurrency, primaryProviders); + + if (!price && this.options.fallbackPrimaryTo) { + [price, providerName] = await this.tryProviders(fromCurrency, this.options.fallbackPrimaryTo, primaryProviders); + } if (!price) { - throw new Error( - `Could not find primary price at: ${primaryProviders.map( - (p) => p.name + ' ', - )}. From ${fromCurrency} to ${toCurrency}`, - ); + throw new Error(this.createPrimaryPriceErrorMessage(primaryProviders, fromCurrency, toCurrency)); } return [price, providerName]; @@ -118,8 +120,8 @@ export class PriceStep { private async getReferencePrice(fromCurrency: string, toCurrency: string): Promise<[Price, PriceProviderName]> { const referenceProviders = this.options.providers.reference; - const [price, providerName] = this.options.referenceTo - ? await this.tryProviders(fromCurrency, this.options.referenceTo, referenceProviders) + const [price, providerName] = this.options.overwriteReferenceTo + ? await this.tryProviders(fromCurrency, this.options.overwriteReferenceTo, referenceProviders) : await this.tryProviders(fromCurrency, toCurrency, referenceProviders); if (!price) { @@ -149,6 +151,20 @@ export class PriceStep { return [null, null]; } + private createPrimaryPriceErrorMessage( + primaryProviders: PriceProvider[], + fromCurrency: string, + toCurrency: string, + ): string { + const mainMessage = `Could not find primary price at: ${primaryProviders.map( + (p) => p.name + ' ', + )}. From ${fromCurrency} to ${toCurrency}. `; + + const fallbackMessage = this.options.fallbackPrimaryTo && `Fallback to currency: ${this.options.fallbackPrimaryTo}`; + + return mainMessage + fallbackMessage; + } + //*** GETTERS ***// get _options(): PriceStepOptions { From f4309fce2601827e8a9108622fa2ab43ecf7b8e6 Mon Sep 17 00:00:00 2001 From: David May Date: Tue, 11 Oct 2022 10:51:56 +0200 Subject: [PATCH 28/30] [DEV-622] Switched to ALTER COLUMN --- migration/1665408086368-assetChainId.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/migration/1665408086368-assetChainId.js b/migration/1665408086368-assetChainId.js index 97fddc4266..ef50c84715 100644 --- a/migration/1665408086368-assetChainId.js +++ b/migration/1665408086368-assetChainId.js @@ -4,12 +4,10 @@ module.exports = class assetChainId1665408086368 { name = 'assetChainId1665408086368' async up(queryRunner) { - await queryRunner.query(`ALTER TABLE "asset" DROP COLUMN "chainId"`); - await queryRunner.query(`ALTER TABLE "asset" ADD "chainId" nvarchar(255)`); + await queryRunner.query(`ALTER TABLE "asset" ALTER COLUMN "chainId" nvarchar(255)`); } async down(queryRunner) { - await queryRunner.query(`ALTER TABLE "asset" DROP COLUMN "chainId"`); - await queryRunner.query(`ALTER TABLE "asset" ADD "chainId" int`); + await queryRunner.query(`ALTER TABLE "asset" ALTER COLUMN "chainId" int`); } } From 0737fc1c2be1461b81e4427887ac3b1ea2d5683b Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Tue, 11 Oct 2022 11:14:41 +0200 Subject: [PATCH 29/30] [DEV-622] added env configuration --- infrastructure/bicep/dfx-api.bicep | 43 +++++++++++++++--------- infrastructure/bicep/parameters/dev.json | 12 +++++++ infrastructure/bicep/parameters/loc.json | 12 +++++++ infrastructure/bicep/parameters/prd.json | 12 +++++++ 4 files changed, 64 insertions(+), 15 deletions(-) diff --git a/infrastructure/bicep/dfx-api.bicep b/infrastructure/bicep/dfx-api.bicep index 947c396481..a83d5ed3c8 100644 --- a/infrastructure/bicep/dfx-api.bicep +++ b/infrastructure/bicep/dfx-api.bicep @@ -45,11 +45,15 @@ param ethWalletPrivateKey string param ethGatewayUrl string @secure() param ethApiKey string +param ethSwapContractAddress string +param ethSwapTokenAddress string param bscWalletAddress string @secure() param bscWalletPrivateKey string param bscGatewayUrl string +param bscSwapContractAddress string +param bscSwapTokenAddress string param nodeServicePlanSkuName string param nodeServicePlanSkuTier string @@ -110,7 +114,6 @@ param myDeFiChainPassword string param paymentUrl string - // --- VARIABLES --- // var compName = 'dfx' var apiName = 'api' @@ -131,7 +134,6 @@ var apiServicePlanName = 'plan-${compName}-${apiName}-${env}' var apiAppName = 'app-${compName}-${apiName}-${env}' var appInsightsName = 'appi-${compName}-${apiName}-${env}' - var nodeProps = [ { name: 'nodes-input-${env}' @@ -243,7 +245,6 @@ resource virtualNet 'Microsoft.Network/virtualNetworks@2020-11-01' = { } } - // Storage Account resource storageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' = { name: storageAccountName @@ -264,7 +265,6 @@ resource dbBackupContainer 'Microsoft.Storage/storageAccounts/blobServices/conta name: '${storageAccount.name}/default/${dbBackupContainerName}' } - // SQL Database resource sqlServer 'Microsoft.Sql/servers@2021-02-01-preview' = { name: sqlServerName @@ -276,11 +276,11 @@ resource sqlServer 'Microsoft.Sql/servers@2021-02-01-preview' = { } resource sqlVNetRule 'Microsoft.Sql/servers/virtualNetworkRules@2021-02-01-preview' = { - parent: sqlServer - name: 'apiVNetRule' - properties: { - virtualNetworkSubnetId: virtualNet.properties.subnets[0].id - } + parent: sqlServer + name: 'apiVNetRule' + properties: { + virtualNetworkSubnetId: virtualNet.properties.subnets[0].id + } } resource sqlAllRule 'Microsoft.Sql/servers/firewallRules@2021-02-01-preview' = if (dbAllowAllIps) { @@ -323,14 +323,13 @@ resource sqlDbLtrPolicy 'Microsoft.Sql/servers/databases/backupLongTermRetention } } - // API App Service resource appServicePlan 'Microsoft.Web/serverfarms@2018-02-01' = { name: apiServicePlanName location: location kind: 'linux' properties: { - reserved: true + reserved: true } sku: { name: 'P1v2' @@ -347,7 +346,7 @@ resource apiAppService 'Microsoft.Web/sites@2018-11-01' = { serverFarmId: appServicePlan.id httpsOnly: true virtualNetworkSubnetId: virtualNet.properties.subnets[0].id - + siteConfig: { alwaysOn: true linuxFxVersion: 'NODE|14-lts' @@ -356,7 +355,7 @@ resource apiAppService 'Microsoft.Web/sites@2018-11-01' = { logsDirectorySizeLimit: 100 vnetRouteAllEnabled: true scmIpSecurityRestrictionsUseMain: true - + appSettings: [ { name: 'APPINSIGHTS_INSTRUMENTATIONKEY' @@ -531,6 +530,14 @@ resource apiAppService 'Microsoft.Web/sites@2018-11-01' = { name: 'ETH_API_KEY' value: ethApiKey } + { + name: 'ETH_SWAP_CONTRACT_ADDRESS' + value: ethSwapContractAddress + } + { + name: 'ETH_SWAP_TOKEN_ADDRESS' + value: ethSwapTokenAddress + } { name: 'BSC_WALLET_ADDRESS' value: bscWalletAddress @@ -543,6 +550,14 @@ resource apiAppService 'Microsoft.Web/sites@2018-11-01' = { name: 'BSC_GATEWAY_URL' value: bscGatewayUrl } + { + name: 'BSC_SWAP_CONTRACT_ADDRESS' + value: bscSwapContractAddress + } + { + name: 'BSC_SWAP_TOKEN_ADDRESS' + value: bscSwapTokenAddress + } { name: 'BTC_COLLECTOR_ADDRESS' value: btcCollectorAddress @@ -672,7 +687,6 @@ resource appInsights 'microsoft.insights/components@2020-02-02-preview' = { } } - // DeFi Nodes module nodes 'defi-node.bicep' = [for node in nodeProps: { name: node.name @@ -692,7 +706,6 @@ module nodes 'defi-node.bicep' = [for node in nodeProps: { } }] - // BTC Node resource vmNsg 'Microsoft.Network/networkSecurityGroups@2020-11-01' = { name: vmNsgName diff --git a/infrastructure/bicep/parameters/dev.json b/infrastructure/bicep/parameters/dev.json index bf28dc6ed0..35f8202c4a 100644 --- a/infrastructure/bicep/parameters/dev.json +++ b/infrastructure/bicep/parameters/dev.json @@ -86,6 +86,12 @@ "ethApiKey": { "value": "xxx" }, + "ethSwapContractAddress": { + "value": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D" + }, + "ethSwapTokenAddress": { + "value": "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6" + }, "bscWalletAddress": { "value": "xxx" }, @@ -95,6 +101,12 @@ "bscGatewayUrl": { "value": "https://data-seed-prebsc-1-s1.binance.org:8545" }, + "bscSwapContractAddress": { + "value": "0xD99D1c33F9fC3444f8101754aBC46c52416550D1" + }, + "bscSwapTokenAddress": { + "value": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd" + }, "btcCollectorAddress": { "value": "xxx" }, diff --git a/infrastructure/bicep/parameters/loc.json b/infrastructure/bicep/parameters/loc.json index 0d49089ab6..bc104c7cef 100644 --- a/infrastructure/bicep/parameters/loc.json +++ b/infrastructure/bicep/parameters/loc.json @@ -86,6 +86,12 @@ "ethApiKey": { "value": "xxx" }, + "ethSwapContractAddress": { + "value": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D" + }, + "ethSwapTokenAddress": { + "value": "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6" + }, "bscWalletAddress": { "value": "xxx" }, @@ -95,6 +101,12 @@ "bscGatewayUrl": { "value": "https://data-seed-prebsc-1-s1.binance.org:8545" }, + "bscSwapContractAddress": { + "value": "0xD99D1c33F9fC3444f8101754aBC46c52416550D1" + }, + "bscSwapTokenAddress": { + "value": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd" + }, "btcCollectorAddress": { "value": "xxx" }, diff --git a/infrastructure/bicep/parameters/prd.json b/infrastructure/bicep/parameters/prd.json index 788b03c565..615b44fdea 100644 --- a/infrastructure/bicep/parameters/prd.json +++ b/infrastructure/bicep/parameters/prd.json @@ -86,6 +86,12 @@ "ethApiKey": { "value": "xxx" }, + "ethSwapContractAddress": { + "value": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D" + }, + "ethSwapTokenAddress": { + "value": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + }, "bscWalletAddress": { "value": "xxx" }, @@ -95,6 +101,12 @@ "bscGatewayUrl": { "value": "https://bsc-dataseed.binance.org" }, + "bscSwapContractAddress": { + "value": "0x10ED43C718714eb63d5aA57B78B54704E256024E" + }, + "bscSwapTokenAddress": { + "value": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c" + }, "btcCollectorAddress": { "value": "xxx" }, From 7028fb7a025a99cf007a57ca16b7783ede0c5f42 Mon Sep 17 00:00:00 2001 From: Anton Semikin Date: Wed, 12 Oct 2022 12:12:53 +0200 Subject: [PATCH 30/30] [DEV-622] addressed PR comments --- src/blockchain/shared/evm/evm-client.ts | 28 ++++-- src/payment/models/dex/dex.module.ts | 8 +- .../models/dex/services/dex-evm.service.ts | 4 +- .../__tests__/check-liquidity.facade.spec.ts | 60 ++++++------- .../check-liquidity/check-liquidity.facade.ts | 26 +++--- ...rypto.strategy.ts => evm-coin.strategy.ts} | 4 +- ...rypto.strategy.ts => bsc-coin.strategy.ts} | 4 +- ....strategy.ts => ethereum-coin.strategy.ts} | 4 +- .../purchase-liquidity.facade.spec.ts | 73 +++++++-------- ...rypto.strategy.ts => evm-coin.strategy.ts} | 4 +- ...rypto.strategy.ts => bsc-coin.strategy.ts} | 4 +- ....strategy.ts => ethereum-coin.strategy.ts} | 4 +- .../purchase-liquidity.facade.ts | 26 +++--- src/payment/models/payout/payout.module.ts | 6 +- .../payout/services/payout-evm.service.ts | 4 +- .../payout/__tests__/payout.facade.spec.ts | 88 +++++++++---------- ...rypto.strategy.ts => bsc-coin.strategy.ts} | 4 +- ...strategy.ts => defichain-coin.strategy.ts} | 2 +- ....strategy.ts => ethereum-coin.strategy.ts} | 4 +- .../payout/strategies/payout/payout.facade.ts | 40 ++++----- .../asset/__mocks__/asset.entity.mock.ts | 5 +- src/shared/models/asset/asset.entity.ts | 3 +- 22 files changed, 198 insertions(+), 207 deletions(-) rename src/payment/models/dex/strategies/check-liquidity/impl/base/{evm-crypto.strategy.ts => evm-coin.strategy.ts} (83%) rename src/payment/models/dex/strategies/check-liquidity/impl/{bsc-crypto.strategy.ts => bsc-coin.strategy.ts} (62%) rename src/payment/models/dex/strategies/check-liquidity/impl/{ethereum-crypto.strategy.ts => ethereum-coin.strategy.ts} (64%) rename src/payment/models/dex/strategies/purchase-liquidity/impl/base/{evm-crypto.strategy.ts => evm-coin.strategy.ts} (89%) rename src/payment/models/dex/strategies/purchase-liquidity/impl/{bsc-crypto.strategy.ts => bsc-coin.strategy.ts} (71%) rename src/payment/models/dex/strategies/purchase-liquidity/impl/{ethereum-crypto.strategy.ts => ethereum-coin.strategy.ts} (72%) rename src/payment/models/payout/strategies/payout/impl/{bsc-crypto.strategy.ts => bsc-coin.strategy.ts} (80%) rename src/payment/models/payout/strategies/payout/impl/{defichain-dfi.strategy.ts => defichain-coin.strategy.ts} (96%) rename src/payment/models/payout/strategies/payout/impl/{ethereum-crypto.strategy.ts => ethereum-coin.strategy.ts} (79%) diff --git a/src/blockchain/shared/evm/evm-client.ts b/src/blockchain/shared/evm/evm-client.ts index 6cdd9fe245..9a40765a14 100644 --- a/src/blockchain/shared/evm/evm-client.ts +++ b/src/blockchain/shared/evm/evm-client.ts @@ -1,4 +1,4 @@ -import { Contract, ethers } from 'ethers'; +import { BigNumber, Contract, ethers } from 'ethers'; import { Asset } from 'src/shared/models/asset/asset.entity'; import * as ERC20_ABI from './abi/erc20.abi.json'; import * as UNISWAP_ROUTER_02_ABI from './abi/uniswap-router02.abi.json'; @@ -25,10 +25,10 @@ export class EvmClient { this.#router = new ethers.Contract(swapContractAddress, UNISWAP_ROUTER_02_ABI, this.#wallet); } - async getNativeCryptoBalance(): Promise { + async getNativeCoinBalance(): Promise { const balance = await this.#provider.getBalance(this.#dfxAddress); - return parseFloat(ethers.utils.formatEther(balance)); + return this.convertToEthLikeDenomination(balance); } async getTokenBalance(token: Asset): Promise { @@ -36,16 +36,16 @@ export class EvmClient { const balance = await contract.balanceOf(this.#dfxAddress); const decimals = await contract.decimals(); - return parseFloat(ethers.utils.formatUnits(balance, decimals)); + return this.convertToEthLikeDenomination(balance, decimals); } - async sendNativeCrypto(address: string, amount: number): Promise { + async sendNativeCoin(address: string, amount: number): Promise { const gasPrice = await this.#provider.getGasPrice(); const tx = await this.#wallet.sendTransaction({ from: this.#dfxAddress, to: address, - value: ethers.utils.parseUnits(`${amount}`, 'ether'), + value: this.convertToWeiLikeDenomination(amount, 'ether'), gasPrice, // has to be provided as a number for BSC gasLimit: 21000, @@ -57,7 +57,7 @@ export class EvmClient { async sendToken(address: string, token: Asset, amount: number): Promise { const contract = this.getERC20Contract(token.chainId); const decimals = await contract.decimals(); - const targetAmount = ethers.utils.parseUnits(`${amount}`, decimals); + const targetAmount = this.convertToWeiLikeDenomination(amount, decimals); const tx = await contract.transfer(address, targetAmount); @@ -76,11 +76,11 @@ export class EvmClient { async nativeCryptoTestSwap(nativeCryptoAmount: number, targetToken: Asset): Promise { const contract = new ethers.Contract(targetToken.chainId, ERC20_ABI, this.#wallet); - const inputAmount = ethers.utils.parseUnits(`${nativeCryptoAmount}`, 'ether'); + const inputAmount = this.convertToWeiLikeDenomination(nativeCryptoAmount, 'ether'); const outputAmounts = await this.#router.getAmountsOut(inputAmount, [this.#swapTokenAddress, targetToken.chainId]); const decimals = await contract.decimals(); - return parseFloat(ethers.utils.formatUnits(outputAmounts[1], decimals)); + return this.convertToEthLikeDenomination(outputAmounts[1], decimals); } //*** HELPER METHODS ***// @@ -95,4 +95,14 @@ export class EvmClient { return tokenContract; } + + private convertToWeiLikeDenomination(amountEthLike: number, decimals: number | 'ether'): BigNumber { + return ethers.utils.parseUnits(`${amountEthLike}`, decimals); + } + + private convertToEthLikeDenomination(amountWeiLike: BigNumber, decimals?: number): number { + return decimals + ? parseFloat(ethers.utils.formatUnits(amountWeiLike, decimals)) + : parseFloat(ethers.utils.formatEther(amountWeiLike)); + } } diff --git a/src/payment/models/dex/dex.module.ts b/src/payment/models/dex/dex.module.ts index fda9de3620..80713e0397 100644 --- a/src/payment/models/dex/dex.module.ts +++ b/src/payment/models/dex/dex.module.ts @@ -15,16 +15,16 @@ import { CheckLiquidityStrategies } from './strategies/check-liquidity/check-liq import { PurchaseLiquidityStrategies } from './strategies/purchase-liquidity/purchase-liquidity.facade'; import { DeFiChainDefaultStrategy as DeFiChainDefaultStrategyCL } from './strategies/check-liquidity/impl/defichain-default.strategy'; import { DeFiChainPoolPairStrategy as DeFiChainPoolPairStrategyCL } from './strategies/check-liquidity/impl/defichain-poolpair.strategy'; -import { EthereumCryptoStrategy as EthereumCryptoStrategyCL } from './strategies/check-liquidity/impl/ethereum-crypto.strategy'; -import { BscCryptoStrategy as BscCryptoStrategyCL } from './strategies/check-liquidity/impl/bsc-crypto.strategy'; +import { EthereumCoinStrategy as EthereumCryptoStrategyCL } from './strategies/check-liquidity/impl/ethereum-coin.strategy'; +import { BscCoinStrategy as BscCryptoStrategyCL } from './strategies/check-liquidity/impl/bsc-coin.strategy'; import { BitcoinStrategy as BitcoinStrategyCL } from './strategies/check-liquidity/impl/bitcoin.strategy'; import { BscTokenStrategy as BscTokenStrategyCL } from './strategies/check-liquidity/impl/bsc-token.strategy'; import { EthereumTokenStrategy as EthereumTokenStrategyCL } from './strategies/check-liquidity/impl/ethereum-token.strategy'; import { DeFiChainCryptoStrategy as DeFiChainCryptoStrategyPL } from './strategies/purchase-liquidity/impl/defichain-crypto.strategy'; import { DeFiChainPoolPairStrategy as DeFiChainPoolPairStrategyPL } from './strategies/purchase-liquidity/impl/defichain-poolpair.strategy'; import { DeFiChainStockStrategy as DeFiChainStockStrategyPL } from './strategies/purchase-liquidity/impl/defichain-stock.strategy'; -import { EthereumCryptoStrategy as EthereumCryptoStrategyPL } from './strategies/purchase-liquidity/impl/ethereum-crypto.strategy'; -import { BscCryptoStrategy as BscCryptoStrategyPL } from './strategies/purchase-liquidity/impl/bsc-crypto.strategy'; +import { EthereumCoinStrategy as EthereumCryptoStrategyPL } from './strategies/purchase-liquidity/impl/ethereum-coin.strategy'; +import { BscCoinStrategy as BscCryptoStrategyPL } from './strategies/purchase-liquidity/impl/bsc-coin.strategy'; import { BitcoinStrategy as BitcoinStrategyPL } from './strategies/purchase-liquidity/impl/bitcoin.strategy'; import { BscTokenStrategy as BscTokenStrategyPL } from './strategies/purchase-liquidity/impl/bsc-token.strategy'; import { EthereumTokenStrategy as EthereumTokenStrategyPL } from './strategies/purchase-liquidity/impl/ethereum-token.strategy'; diff --git a/src/payment/models/dex/services/dex-evm.service.ts b/src/payment/models/dex/services/dex-evm.service.ts index 3bc692c461..ba3fd7fea2 100644 --- a/src/payment/models/dex/services/dex-evm.service.ts +++ b/src/payment/models/dex/services/dex-evm.service.ts @@ -19,9 +19,9 @@ export abstract class DexEvmService { this.#client = service.getDefaultClient(); } - async checkNativeCryptoAvailability(amount: number): Promise { + async checkNativeCoinAvailability(amount: number): Promise { const pendingAmount = await this.getPendingAmount(this.nativeCoin); - const availableAmount = await this.#client.getNativeCryptoBalance(); + const availableAmount = await this.#client.getNativeCoinBalance(); this.checkLiquidity(amount, pendingAmount, availableAmount, this.nativeCoin); diff --git a/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts b/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts index a64d639906..bf692e6f4d 100644 --- a/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts +++ b/src/payment/models/dex/strategies/check-liquidity/__tests__/check-liquidity.facade.spec.ts @@ -2,16 +2,16 @@ import { mock } from 'jest-mock-extended'; import { BehaviorSubject } from 'rxjs'; import { NodeService } from 'src/blockchain/ain/node/node.service'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { AssetCategory } from 'src/shared/models/asset/asset.entity'; +import { AssetCategory, AssetType } from 'src/shared/models/asset/asset.entity'; import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; import { DexBscService } from '../../../services/dex-bsc.service'; import { DexDeFiChainService } from '../../../services/dex-defichain.service'; import { DexEthereumService } from '../../../services/dex-ethereum.service'; import { CheckLiquidityStrategies } from '../check-liquidity.facade'; -import { BscCryptoStrategy } from '../impl/bsc-crypto.strategy'; +import { BscCoinStrategy } from '../impl/bsc-coin.strategy'; import { DeFiChainDefaultStrategy } from '../impl/defichain-default.strategy'; import { DeFiChainPoolPairStrategy } from '../impl/defichain-poolpair.strategy'; -import { EthereumCryptoStrategy } from '../impl/ethereum-crypto.strategy'; +import { EthereumCoinStrategy } from '../impl/ethereum-coin.strategy'; import { CheckLiquidityAlias } from '../check-liquidity.facade'; import { BitcoinStrategy } from '../impl/bitcoin.strategy'; import { BscTokenStrategy } from '../impl/bsc-token.strategy'; @@ -22,11 +22,11 @@ describe('CheckLiquidityStrategies', () => { let nodeService: NodeService; let bitcoin: BitcoinStrategy; - let bscCrypto: BscCryptoStrategy; + let bscCoin: BscCoinStrategy; let bscToken: BscTokenStrategy; let deFiChainPoolPair: DeFiChainPoolPairStrategy; let deFiChainDefault: DeFiChainDefaultStrategy; - let ethereumCrypto: EthereumCryptoStrategy; + let ethereumCoin: EthereumCoinStrategy; let ethereumToken: EthereumTokenStrategy; let facade: CheckLiquidityStrategiesWrapper; @@ -36,20 +36,20 @@ describe('CheckLiquidityStrategies', () => { jest.spyOn(nodeService, 'getConnectedNode').mockImplementation(() => new BehaviorSubject(null)); bitcoin = new BitcoinStrategy(mock()); - bscCrypto = new BscCryptoStrategy(mock()); + bscCoin = new BscCoinStrategy(mock()); bscToken = new BscTokenStrategy(mock()); deFiChainPoolPair = new DeFiChainPoolPairStrategy(); deFiChainDefault = new DeFiChainDefaultStrategy(mock()); - ethereumCrypto = new EthereumCryptoStrategy(mock()); + ethereumCoin = new EthereumCoinStrategy(mock()); ethereumToken = new EthereumTokenStrategy(mock()); facade = new CheckLiquidityStrategiesWrapper( bitcoin, - bscCrypto, + bscCoin, bscToken, deFiChainDefault, deFiChainPoolPair, - ethereumCrypto, + ethereumCoin, ethereumToken, ); }); @@ -67,17 +67,17 @@ describe('CheckLiquidityStrategies', () => { const aliases = [...facade.getStrategies().keys()]; expect(aliases.includes(CheckLiquidityAlias.BITCOIN)).toBe(true); - expect(aliases.includes(CheckLiquidityAlias.BSC_CRYPTO)).toBe(true); + expect(aliases.includes(CheckLiquidityAlias.BSC_COIN)).toBe(true); expect(aliases.includes(CheckLiquidityAlias.BSC_TOKEN)).toBe(true); expect(aliases.includes(CheckLiquidityAlias.DEFICHAIN_POOL_PAIR)).toBe(true); expect(aliases.includes(CheckLiquidityAlias.DEFICHAIN_DEFAULT)).toBe(true); - expect(aliases.includes(CheckLiquidityAlias.ETHEREUM_CRYPTO)).toBe(true); + expect(aliases.includes(CheckLiquidityAlias.ETHEREUM_COIN)).toBe(true); expect(aliases.includes(CheckLiquidityAlias.ETHEREUM_TOKEN)).toBe(true); }); it('assigns proper checkLiquidityStrategies to aliases', () => { expect(facade.getStrategies().get(CheckLiquidityAlias.BITCOIN)).toBeInstanceOf(BitcoinStrategy); - expect(facade.getStrategies().get(CheckLiquidityAlias.BSC_CRYPTO)).toBeInstanceOf(BscCryptoStrategy); + expect(facade.getStrategies().get(CheckLiquidityAlias.BSC_COIN)).toBeInstanceOf(BscCoinStrategy); expect(facade.getStrategies().get(CheckLiquidityAlias.BSC_TOKEN)).toBeInstanceOf(BscTokenStrategy); expect(facade.getStrategies().get(CheckLiquidityAlias.DEFICHAIN_POOL_PAIR)).toBeInstanceOf( DeFiChainPoolPairStrategy, @@ -85,7 +85,7 @@ describe('CheckLiquidityStrategies', () => { expect(facade.getStrategies().get(CheckLiquidityAlias.DEFICHAIN_DEFAULT)).toBeInstanceOf( DeFiChainDefaultStrategy, ); - expect(facade.getStrategies().get(CheckLiquidityAlias.ETHEREUM_CRYPTO)).toBeInstanceOf(EthereumCryptoStrategy); + expect(facade.getStrategies().get(CheckLiquidityAlias.ETHEREUM_COIN)).toBeInstanceOf(EthereumCoinStrategy); expect(facade.getStrategies().get(CheckLiquidityAlias.ETHEREUM_TOKEN)).toBeInstanceOf(EthereumTokenStrategy); }); }); @@ -98,17 +98,17 @@ describe('CheckLiquidityStrategies', () => { expect(strategy).toBeInstanceOf(BitcoinStrategy); }); - it('gets BSC_CRYPTO strategy', () => { + it('gets BSC_COIN strategy', () => { const strategy = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.CRYPTO }), + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, type: AssetType.COIN }), ); - expect(strategy).toBeInstanceOf(BscCryptoStrategy); + expect(strategy).toBeInstanceOf(BscCoinStrategy); }); it('gets BSC_TOKEN strategy', () => { const strategy = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.STOCK }), + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, type: AssetType.TOKEN }), ); expect(strategy).toBeInstanceOf(BscTokenStrategy); @@ -136,17 +136,17 @@ describe('CheckLiquidityStrategies', () => { expect(strategyStock).toBeInstanceOf(DeFiChainDefaultStrategy); }); - it('gets ETHEREUM_CRYPTO strategy', () => { + it('gets ETHEREUM_COIN strategy', () => { const strategy = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.CRYPTO }), + createCustomAsset({ blockchain: Blockchain.ETHEREUM, type: AssetType.COIN }), ); - expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + expect(strategy).toBeInstanceOf(EthereumCoinStrategy); }); it('gets ETHEREUM_TOKEN strategy', () => { const strategy = facade.getCheckLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.STOCK }), + createCustomAsset({ blockchain: Blockchain.ETHEREUM, type: AssetType.TOKEN }), ); expect(strategy).toBeInstanceOf(EthereumTokenStrategy); @@ -168,10 +168,10 @@ describe('CheckLiquidityStrategies', () => { expect(strategy).toBeInstanceOf(BitcoinStrategy); }); - it('gets BSC_CRYPTO strategy', () => { - const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.BSC_CRYPTO); + it('gets BSC_COIN strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.BSC_COIN); - expect(strategy).toBeInstanceOf(BscCryptoStrategy); + expect(strategy).toBeInstanceOf(BscCoinStrategy); }); it('gets BSC_TOKEN strategy', () => { @@ -192,10 +192,10 @@ describe('CheckLiquidityStrategies', () => { expect(strategyCrypto).toBeInstanceOf(DeFiChainDefaultStrategy); }); - it('gets ETHEREUM_CRYPTO strategy', () => { - const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.ETHEREUM_CRYPTO); + it('gets ETHEREUM_COIN strategy', () => { + const strategy = facade.getCheckLiquidityStrategy(CheckLiquidityAlias.ETHEREUM_COIN); - expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + expect(strategy).toBeInstanceOf(EthereumCoinStrategy); }); it('gets ETHEREUM_TOKEN strategy', () => { @@ -218,14 +218,14 @@ describe('CheckLiquidityStrategies', () => { class CheckLiquidityStrategiesWrapper extends CheckLiquidityStrategies { constructor( bitcoin: BitcoinStrategy, - bscCrypto: BscCryptoStrategy, + bscCoin: BscCoinStrategy, bscToken: BscTokenStrategy, deFiChainDefault: DeFiChainDefaultStrategy, deFiChainPoolPair: DeFiChainPoolPairStrategy, - ethereumCrypto: EthereumCryptoStrategy, + ethereumCoin: EthereumCoinStrategy, ethereumToken: EthereumTokenStrategy, ) { - super(bitcoin, bscCrypto, bscToken, deFiChainDefault, deFiChainPoolPair, ethereumCrypto, ethereumToken); + super(bitcoin, bscCoin, bscToken, deFiChainDefault, deFiChainPoolPair, ethereumCoin, ethereumToken); } getStrategies() { diff --git a/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts b/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts index 9589548483..5d78660a68 100644 --- a/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts +++ b/src/payment/models/dex/strategies/check-liquidity/check-liquidity.facade.ts @@ -1,22 +1,22 @@ import { Injectable } from '@nestjs/common'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { Asset, AssetCategory } from 'src/shared/models/asset/asset.entity'; +import { Asset, AssetCategory, AssetType } from 'src/shared/models/asset/asset.entity'; import { CheckLiquidityStrategy } from './impl/base/check-liquidity.strategy'; import { BitcoinStrategy } from './impl/bitcoin.strategy'; -import { BscCryptoStrategy } from './impl/bsc-crypto.strategy'; +import { BscCoinStrategy } from './impl/bsc-coin.strategy'; import { BscTokenStrategy } from './impl/bsc-token.strategy'; import { DeFiChainDefaultStrategy } from './impl/defichain-default.strategy'; import { DeFiChainPoolPairStrategy } from './impl/defichain-poolpair.strategy'; -import { EthereumCryptoStrategy } from './impl/ethereum-crypto.strategy'; +import { EthereumCoinStrategy } from './impl/ethereum-coin.strategy'; import { EthereumTokenStrategy } from './impl/ethereum-token.strategy'; enum Alias { BITCOIN = 'Bitcoin', - BSC_CRYPTO = 'BscCrypto', + BSC_COIN = 'BscCoin', BSC_TOKEN = 'BscToken', DEFICHAIN_POOL_PAIR = 'DeFiChainPoolPair', DEFICHAIN_DEFAULT = 'DeFiChainDefault', - ETHEREUM_CRYPTO = 'EthereumCrypto', + ETHEREUM_COIN = 'EthereumCoin', ETHEREUM_TOKEN = 'EthereumToken', } @@ -28,19 +28,19 @@ export class CheckLiquidityStrategies { constructor( bitcoin: BitcoinStrategy, - bscCrypto: BscCryptoStrategy, + bscCoin: BscCoinStrategy, bscToken: BscTokenStrategy, deFiChainDefault: DeFiChainDefaultStrategy, deFiChainPoolPair: DeFiChainPoolPairStrategy, - ethereumCrypto: EthereumCryptoStrategy, + ethereumCoin: EthereumCoinStrategy, ethereumToken: EthereumTokenStrategy, ) { this.strategies.set(Alias.BITCOIN, bitcoin); - this.strategies.set(Alias.BSC_CRYPTO, bscCrypto); + this.strategies.set(Alias.BSC_COIN, bscCoin); this.strategies.set(Alias.BSC_TOKEN, bscToken); this.strategies.set(Alias.DEFICHAIN_POOL_PAIR, deFiChainPoolPair); this.strategies.set(Alias.DEFICHAIN_DEFAULT, deFiChainDefault); - this.strategies.set(Alias.ETHEREUM_CRYPTO, ethereumCrypto); + this.strategies.set(Alias.ETHEREUM_COIN, ethereumCoin); this.strategies.set(Alias.ETHEREUM_TOKEN, ethereumToken); } @@ -65,13 +65,12 @@ export class CheckLiquidityStrategies { } private getAlias(asset: Asset): Alias { - const { blockchain, category: assetCategory } = asset; + const { blockchain, category: assetCategory, type: assetType } = asset; if (blockchain === Blockchain.BITCOIN) return Alias.BITCOIN; if (blockchain === Blockchain.BINANCE_SMART_CHAIN) { - if (assetCategory === AssetCategory.CRYPTO) return Alias.BSC_CRYPTO; - if (assetCategory === AssetCategory.STOCK) return Alias.BSC_TOKEN; + return assetType === AssetType.COIN ? Alias.BSC_COIN : Alias.BSC_TOKEN; } if (blockchain === Blockchain.DEFICHAIN) { @@ -80,8 +79,7 @@ export class CheckLiquidityStrategies { } if (blockchain === Blockchain.ETHEREUM) { - if (assetCategory === AssetCategory.CRYPTO) return Alias.ETHEREUM_CRYPTO; - if (assetCategory === AssetCategory.STOCK) return Alias.ETHEREUM_TOKEN; + return assetType === AssetType.COIN ? Alias.ETHEREUM_COIN : Alias.ETHEREUM_TOKEN; } } } diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-coin.strategy.ts similarity index 83% rename from src/payment/models/dex/strategies/check-liquidity/impl/base/evm-crypto.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/impl/base/evm-coin.strategy.ts index 7ae7ef9dd9..66533c2ec5 100644 --- a/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/base/evm-coin.strategy.ts @@ -2,14 +2,14 @@ import { LiquidityRequest } from '../../../../interfaces'; import { DexEvmService } from '../../../../services/dex-evm.service'; import { CheckLiquidityStrategy } from './check-liquidity.strategy'; -export class EvmCryptoStrategy implements CheckLiquidityStrategy { +export class EvmCoinStrategy implements CheckLiquidityStrategy { constructor(protected readonly dexEvmService: DexEvmService) {} async checkLiquidity(request: LiquidityRequest): Promise { const { referenceAsset, referenceAmount, context, correlationId } = request; if (referenceAsset === this.dexEvmService._nativeCoin) { - return this.dexEvmService.checkNativeCryptoAvailability(referenceAmount); + return this.dexEvmService.checkNativeCoinAvailability(referenceAmount); } // only native coin is enabled as a referenceAsset diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/bsc-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/bsc-coin.strategy.ts similarity index 62% rename from src/payment/models/dex/strategies/check-liquidity/impl/bsc-crypto.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/impl/bsc-coin.strategy.ts index 263d677ce7..4f30518cbd 100644 --- a/src/payment/models/dex/strategies/check-liquidity/impl/bsc-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/bsc-coin.strategy.ts @@ -1,9 +1,9 @@ import { Injectable } from '@nestjs/common'; import { DexBscService } from '../../../services/dex-bsc.service'; -import { EvmCryptoStrategy } from './base/evm-crypto.strategy'; +import { EvmCoinStrategy } from './base/evm-coin.strategy'; @Injectable() -export class BscCryptoStrategy extends EvmCryptoStrategy { +export class BscCoinStrategy extends EvmCoinStrategy { constructor(dexBscService: DexBscService) { super(dexBscService); } diff --git a/src/payment/models/dex/strategies/check-liquidity/impl/ethereum-crypto.strategy.ts b/src/payment/models/dex/strategies/check-liquidity/impl/ethereum-coin.strategy.ts similarity index 64% rename from src/payment/models/dex/strategies/check-liquidity/impl/ethereum-crypto.strategy.ts rename to src/payment/models/dex/strategies/check-liquidity/impl/ethereum-coin.strategy.ts index b2899ee33e..b49b957298 100644 --- a/src/payment/models/dex/strategies/check-liquidity/impl/ethereum-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/check-liquidity/impl/ethereum-coin.strategy.ts @@ -1,9 +1,9 @@ import { Injectable } from '@nestjs/common'; import { DexEthereumService } from '../../../services/dex-ethereum.service'; -import { EvmCryptoStrategy } from './base/evm-crypto.strategy'; +import { EvmCoinStrategy } from './base/evm-coin.strategy'; @Injectable() -export class EthereumCryptoStrategy extends EvmCryptoStrategy { +export class EthereumCoinStrategy extends EvmCoinStrategy { constructor(dexEthereumService: DexEthereumService) { super(dexEthereumService); } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts b/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts index ae1d865a98..54fd72c8ed 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/__tests__/purchase-liquidity.facade.spec.ts @@ -2,7 +2,7 @@ import { mock } from 'jest-mock-extended'; import { BehaviorSubject } from 'rxjs'; import { NodeService } from 'src/blockchain/ain/node/node.service'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { AssetCategory } from 'src/shared/models/asset/asset.entity'; +import { AssetCategory, AssetType } from 'src/shared/models/asset/asset.entity'; import { AssetService } from 'src/shared/models/asset/asset.service'; import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; import { SettingService } from 'src/shared/models/setting/setting.service'; @@ -14,12 +14,12 @@ import { DexBscService } from '../../../services/dex-bsc.service'; import { DexDeFiChainService } from '../../../services/dex-defichain.service'; import { DexService } from '../../../services/dex.service'; import { BitcoinStrategy } from '../impl/bitcoin.strategy'; -import { BscCryptoStrategy } from '../impl/bsc-crypto.strategy'; +import { BscCoinStrategy } from '../impl/bsc-coin.strategy'; import { BscTokenStrategy } from '../impl/bsc-token.strategy'; import { DeFiChainCryptoStrategy } from '../impl/defichain-crypto.strategy'; import { DeFiChainPoolPairStrategy } from '../impl/defichain-poolpair.strategy'; import { DeFiChainStockStrategy } from '../impl/defichain-stock.strategy'; -import { EthereumCryptoStrategy } from '../impl/ethereum-crypto.strategy'; +import { EthereumCoinStrategy } from '../impl/ethereum-coin.strategy'; import { EthereumTokenStrategy } from '../impl/ethereum-token.strategy'; import { PurchaseLiquidityStrategyAlias, PurchaseLiquidityStrategies } from '../purchase-liquidity.facade'; @@ -27,12 +27,12 @@ describe('PurchaseLiquidityStrategies', () => { let nodeService: NodeService; let bitcoin: BitcoinStrategy; - let bscCrypto: BscCryptoStrategy; + let bscCoin: BscCoinStrategy; let bscToken: BscTokenStrategy; let deFiChainPoolPair: DeFiChainPoolPairStrategy; let deFiChainStock: DeFiChainStockStrategy; let deFiChainCrypto: DeFiChainCryptoStrategy; - let ethereumCrypto: EthereumCryptoStrategy; + let ethereumCoin: EthereumCoinStrategy; let ethereumToken: EthereumTokenStrategy; let facade: PurchaseLiquidityStrategiesWrapper; @@ -42,7 +42,7 @@ describe('PurchaseLiquidityStrategies', () => { jest.spyOn(nodeService, 'getConnectedNode').mockImplementation(() => new BehaviorSubject(null)); bitcoin = new BitcoinStrategy(mock(), mock()); - bscCrypto = new BscCryptoStrategy(mock(), mock()); + bscCoin = new BscCoinStrategy(mock(), mock()); bscToken = new BscTokenStrategy(mock(), mock()); deFiChainPoolPair = new DeFiChainPoolPairStrategy( @@ -66,17 +66,17 @@ describe('PurchaseLiquidityStrategies', () => { mock(), mock(), ); - ethereumCrypto = new EthereumCryptoStrategy(mock(), mock()); + ethereumCoin = new EthereumCoinStrategy(mock(), mock()); ethereumToken = new EthereumTokenStrategy(mock(), mock()); facade = new PurchaseLiquidityStrategiesWrapper( bitcoin, - bscCrypto, + bscCoin, bscToken, deFiChainCrypto, deFiChainPoolPair, deFiChainStock, - ethereumCrypto, + ethereumCoin, ethereumToken, ); }); @@ -94,18 +94,18 @@ describe('PurchaseLiquidityStrategies', () => { const aliases = [...facade.getStrategies().keys()]; expect(aliases.includes(PurchaseLiquidityStrategyAlias.BITCOIN)).toBe(true); - expect(aliases.includes(PurchaseLiquidityStrategyAlias.BSC_CRYPTO)).toBe(true); + expect(aliases.includes(PurchaseLiquidityStrategyAlias.BSC_COIN)).toBe(true); expect(aliases.includes(PurchaseLiquidityStrategyAlias.BSC_TOKEN)).toBe(true); expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_POOL_PAIR)).toBe(true); expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK)).toBe(true); expect(aliases.includes(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO)).toBe(true); - expect(aliases.includes(PurchaseLiquidityStrategyAlias.ETHEREUM_CRYPTO)).toBe(true); + expect(aliases.includes(PurchaseLiquidityStrategyAlias.ETHEREUM_COIN)).toBe(true); expect(aliases.includes(PurchaseLiquidityStrategyAlias.ETHEREUM_TOKEN)).toBe(true); }); it('assigns proper purchaseLiquidityStrategies to aliases', () => { expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.BITCOIN)).toBeInstanceOf(BitcoinStrategy); - expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.BSC_CRYPTO)).toBeInstanceOf(BscCryptoStrategy); + expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.BSC_COIN)).toBeInstanceOf(BscCoinStrategy); expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.BSC_TOKEN)).toBeInstanceOf(BscTokenStrategy); expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_CRYPTO)).toBeInstanceOf( DeFiChainCryptoStrategy, @@ -116,8 +116,8 @@ describe('PurchaseLiquidityStrategies', () => { expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.DEFICHAIN_STOCK)).toBeInstanceOf( DeFiChainStockStrategy, ); - expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.ETHEREUM_CRYPTO)).toBeInstanceOf( - EthereumCryptoStrategy, + expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.ETHEREUM_COIN)).toBeInstanceOf( + EthereumCoinStrategy, ); expect(facade.getStrategies().get(PurchaseLiquidityStrategyAlias.ETHEREUM_TOKEN)).toBeInstanceOf( EthereumTokenStrategy, @@ -133,17 +133,17 @@ describe('PurchaseLiquidityStrategies', () => { expect(strategy).toBeInstanceOf(BitcoinStrategy); }); - it('gets BSC_CRYPTO strategy', () => { + it('gets BSC_COIN strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.CRYPTO }), + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, type: AssetType.COIN }), ); - expect(strategy).toBeInstanceOf(BscCryptoStrategy); + expect(strategy).toBeInstanceOf(BscCoinStrategy); }); it('gets BSC_TOKEN strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.STOCK }), + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, type: AssetType.TOKEN }), ); expect(strategy).toBeInstanceOf(BscTokenStrategy); @@ -173,17 +173,17 @@ describe('PurchaseLiquidityStrategies', () => { expect(strategy).toBeInstanceOf(DeFiChainStockStrategy); }); - it('gets ETHEREUM_CRYPTO strategy', () => { + it('gets ETHEREUM_COIN strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.CRYPTO }), + createCustomAsset({ blockchain: Blockchain.ETHEREUM, type: AssetType.COIN }), ); - expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + expect(strategy).toBeInstanceOf(EthereumCoinStrategy); }); it('gets ETHEREUM_TOKEN strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy( - createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.STOCK }), + createCustomAsset({ blockchain: Blockchain.ETHEREUM, type: AssetType.TOKEN }), ); expect(strategy).toBeInstanceOf(EthereumTokenStrategy); @@ -209,16 +209,16 @@ describe('PurchaseLiquidityStrategies', () => { }); describe('getting strategy by Alias', () => { - it('gets BSC_CRYPTO strategy', () => { + it('gets BITCOIN strategy', () => { const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.BITCOIN); expect(strategy).toBeInstanceOf(BitcoinStrategy); }); - it('gets BSC_CRYPTO strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.BSC_CRYPTO); + it('gets BSC_COIN strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.BSC_COIN); - expect(strategy).toBeInstanceOf(BscCryptoStrategy); + expect(strategy).toBeInstanceOf(BscCoinStrategy); }); it('gets BSC_TOKEN strategy', () => { @@ -245,10 +245,10 @@ describe('PurchaseLiquidityStrategies', () => { expect(strategyCrypto).toBeInstanceOf(DeFiChainStockStrategy); }); - it('gets ETHEREUM_CRYPTO strategy', () => { - const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.ETHEREUM_CRYPTO); + it('gets ETHEREUM_COIN strategy', () => { + const strategy = facade.getPurchaseLiquidityStrategy(PurchaseLiquidityStrategyAlias.ETHEREUM_COIN); - expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + expect(strategy).toBeInstanceOf(EthereumCoinStrategy); }); it('gets ETHEREUM_TOKEN strategy', () => { @@ -271,24 +271,15 @@ describe('PurchaseLiquidityStrategies', () => { class PurchaseLiquidityStrategiesWrapper extends PurchaseLiquidityStrategies { constructor( bitcoin: BitcoinStrategy, - bscCrypto: BscCryptoStrategy, + bscCoin: BscCoinStrategy, bscToken: BscTokenStrategy, deFiChainCrypto: DeFiChainCryptoStrategy, deFiChainPoolPair: DeFiChainPoolPairStrategy, deFiChainStock: DeFiChainStockStrategy, - ethereumCrypto: EthereumCryptoStrategy, + ethereumCoin: EthereumCoinStrategy, ethereumToken: EthereumTokenStrategy, ) { - super( - bitcoin, - bscCrypto, - bscToken, - deFiChainCrypto, - deFiChainPoolPair, - deFiChainStock, - ethereumCrypto, - ethereumToken, - ); + super(bitcoin, bscCoin, bscToken, deFiChainCrypto, deFiChainPoolPair, deFiChainStock, ethereumCoin, ethereumToken); } getStrategies() { diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-coin.strategy.ts similarity index 89% rename from src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-coin.strategy.ts index 4599342b2d..f5a34374c4 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/base/evm-coin.strategy.ts @@ -3,7 +3,7 @@ import { LiquidityRequest } from '../../../../interfaces'; import { DexEvmService } from '../../../../services/dex-evm.service'; import { PurchaseLiquidityStrategy } from './purchase-liquidity.strategy'; -export class EvmCryptoStrategy extends PurchaseLiquidityStrategy { +export class EvmCoinStrategy extends PurchaseLiquidityStrategy { constructor(mailService: MailService, protected readonly dexEvmService: DexEvmService) { super(mailService); } @@ -14,7 +14,7 @@ export class EvmCryptoStrategy extends PurchaseLiquidityStrategy { try { // should always throw, even if there is amount, additional check is done for API consistency and sending mail if (referenceAsset === this.dexEvmService._nativeCoin) { - const amount = await this.dexEvmService.checkNativeCryptoAvailability(referenceAmount); + const amount = await this.dexEvmService.checkNativeCoinAvailability(referenceAmount); if (amount) { throw new Error( diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-coin.strategy.ts similarity index 71% rename from src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-crypto.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-coin.strategy.ts index f8665deaf9..6cf0964362 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/bsc-coin.strategy.ts @@ -1,10 +1,10 @@ import { Injectable } from '@nestjs/common'; import { MailService } from 'src/shared/services/mail.service'; import { DexBscService } from '../../../services/dex-bsc.service'; -import { EvmCryptoStrategy } from './base/evm-crypto.strategy'; +import { EvmCoinStrategy } from './base/evm-coin.strategy'; @Injectable() -export class BscCryptoStrategy extends EvmCryptoStrategy { +export class BscCoinStrategy extends EvmCoinStrategy { constructor(mailService: MailService, dexBscService: DexBscService) { super(mailService, dexBscService); } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-crypto.strategy.ts b/src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-coin.strategy.ts similarity index 72% rename from src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-crypto.strategy.ts rename to src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-coin.strategy.ts index 47df137301..794707cf53 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-crypto.strategy.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/impl/ethereum-coin.strategy.ts @@ -1,10 +1,10 @@ import { Injectable } from '@nestjs/common'; import { MailService } from 'src/shared/services/mail.service'; import { DexEthereumService } from '../../../services/dex-ethereum.service'; -import { EvmCryptoStrategy } from './base/evm-crypto.strategy'; +import { EvmCoinStrategy } from './base/evm-coin.strategy'; @Injectable() -export class EthereumCryptoStrategy extends EvmCryptoStrategy { +export class EthereumCoinStrategy extends EvmCoinStrategy { constructor(mailService: MailService, dexEthereumService: DexEthereumService) { super(mailService, dexEthereumService); } diff --git a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts index fcdebfb2bc..b5ef8b4476 100644 --- a/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts +++ b/src/payment/models/dex/strategies/purchase-liquidity/purchase-liquidity.facade.ts @@ -1,9 +1,9 @@ import { forwardRef, Inject, Injectable } from '@nestjs/common'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { Asset, AssetCategory } from 'src/shared/models/asset/asset.entity'; -import { BscCryptoStrategy } from './impl/bsc-crypto.strategy'; +import { Asset, AssetCategory, AssetType } from 'src/shared/models/asset/asset.entity'; +import { BscCoinStrategy } from './impl/bsc-coin.strategy'; import { DeFiChainCryptoStrategy } from './impl/defichain-crypto.strategy'; -import { EthereumCryptoStrategy } from './impl/ethereum-crypto.strategy'; +import { EthereumCoinStrategy } from './impl/ethereum-coin.strategy'; import { PurchaseLiquidityStrategy } from './impl/base/purchase-liquidity.strategy'; import { DeFiChainPoolPairStrategy } from './impl/defichain-poolpair.strategy'; import { DeFiChainStockStrategy } from './impl/defichain-stock.strategy'; @@ -13,12 +13,12 @@ import { EthereumTokenStrategy } from './impl/ethereum-token.strategy'; enum Alias { BITCOIN = 'Bitcoin', - BSC_CRYPTO = 'BscCrypto', + BSC_COIN = 'BscCoin', BSC_TOKEN = 'BscToken', DEFICHAIN_POOL_PAIR = 'DeFiChainPoolPair', DEFICHAIN_STOCK = 'DeFiChainStock', DEFICHAIN_CRYPTO = 'DeFiChainCrypto', - ETHEREUM_CRYPTO = 'EthereumCrypto', + ETHEREUM_COIN = 'EthereumCoin', ETHEREUM_TOKEN = 'EthereumToken', } @@ -30,22 +30,22 @@ export class PurchaseLiquidityStrategies { constructor( bitcoin: BitcoinStrategy, - bscCrypto: BscCryptoStrategy, + bscCoin: BscCoinStrategy, bscToken: BscTokenStrategy, deFiChainCrypto: DeFiChainCryptoStrategy, @Inject(forwardRef(() => DeFiChainPoolPairStrategy)) deFiChainPoolPair: DeFiChainPoolPairStrategy, deFiChainStock: DeFiChainStockStrategy, - ethereumCrypto: EthereumCryptoStrategy, + ethereumCoin: EthereumCoinStrategy, ethereumToken: EthereumTokenStrategy, ) { this.strategies.set(Alias.BITCOIN, bitcoin); - this.strategies.set(Alias.BSC_CRYPTO, bscCrypto); + this.strategies.set(Alias.BSC_COIN, bscCoin); this.strategies.set(Alias.BSC_TOKEN, bscToken); this.strategies.set(Alias.DEFICHAIN_POOL_PAIR, deFiChainPoolPair); this.strategies.set(Alias.DEFICHAIN_STOCK, deFiChainStock); this.strategies.set(Alias.DEFICHAIN_CRYPTO, deFiChainCrypto); - this.strategies.set(Alias.ETHEREUM_CRYPTO, ethereumCrypto); + this.strategies.set(Alias.ETHEREUM_COIN, ethereumCoin); this.strategies.set(Alias.ETHEREUM_TOKEN, ethereumToken); } @@ -70,13 +70,12 @@ export class PurchaseLiquidityStrategies { } private getAlias(asset: Asset): Alias { - const { blockchain, category: assetCategory } = asset; + const { blockchain, category: assetCategory, type: assetType } = asset; if (blockchain === Blockchain.BITCOIN) return Alias.BITCOIN; if (blockchain === Blockchain.BINANCE_SMART_CHAIN) { - if (assetCategory === AssetCategory.CRYPTO) return Alias.BSC_CRYPTO; - if (assetCategory === AssetCategory.STOCK) return Alias.BSC_TOKEN; + return assetType === AssetType.COIN ? Alias.BSC_COIN : Alias.BSC_TOKEN; } if (blockchain === Blockchain.DEFICHAIN) { @@ -86,8 +85,7 @@ export class PurchaseLiquidityStrategies { } if (blockchain === Blockchain.ETHEREUM) { - if (assetCategory === AssetCategory.CRYPTO) return Alias.ETHEREUM_CRYPTO; - if (assetCategory === AssetCategory.STOCK) return Alias.ETHEREUM_TOKEN; + return assetType === AssetType.COIN ? Alias.ETHEREUM_COIN : Alias.ETHEREUM_TOKEN; } } } diff --git a/src/payment/models/payout/payout.module.ts b/src/payment/models/payout/payout.module.ts index 7d03e77162..f4bf4151cc 100644 --- a/src/payment/models/payout/payout.module.ts +++ b/src/payment/models/payout/payout.module.ts @@ -16,11 +16,11 @@ import { PayoutStrategiesFacade } from './strategies/payout/payout.facade'; import { PayoutBitcoinService } from './services/payout-bitcoin.service'; import { PrepareStrategiesFacade } from './strategies/prepare/prepare.facade'; import { BitcoinStrategy as BitcoinStrategyPO } from './strategies/payout/impl/bitcoin.strategy'; -import { BscCryptoStrategy as BscCryptoStrategyPO } from './strategies/payout/impl/bsc-crypto.strategy'; +import { BscCoinStrategy as BscCryptoStrategyPO } from './strategies/payout/impl/bsc-coin.strategy'; import { BscTokenStrategy as BscTokenStrategyPO } from './strategies/payout/impl/bsc-token.strategy'; -import { DeFiChainDfiStrategy as DeFiChainDfiStrategyPO } from './strategies/payout/impl/defichain-dfi.strategy'; +import { DeFiChainCoinStrategy as DeFiChainDfiStrategyPO } from './strategies/payout/impl/defichain-coin.strategy'; import { DeFiChainTokenStrategy as DeFiChainTokenStrategyPO } from './strategies/payout/impl/defichain-token.strategy'; -import { EthereumCryptoStrategy as EthereumCryptoStrategyPO } from './strategies/payout/impl/ethereum-crypto.strategy'; +import { EthereumCoinStrategy as EthereumCryptoStrategyPO } from './strategies/payout/impl/ethereum-coin.strategy'; import { EthereumTokenStrategy as EthereumTokenStrategyPO } from './strategies/payout/impl/ethereum-token.strategy'; import { BitcoinStrategy as BitcoinStrategyPR } from './strategies/prepare/impl/bitcoin.strategy'; import { BscStrategy as BscStrategyPR } from './strategies/prepare/impl/bsc.strategy'; diff --git a/src/payment/models/payout/services/payout-evm.service.ts b/src/payment/models/payout/services/payout-evm.service.ts index 64c9a19f9a..a89ec253e4 100644 --- a/src/payment/models/payout/services/payout-evm.service.ts +++ b/src/payment/models/payout/services/payout-evm.service.ts @@ -9,8 +9,8 @@ export abstract class PayoutEvmService { this.#client = service.getDefaultClient(); } - async sendNativeCrypto(address: string, amount: number): Promise { - return this.#client.sendNativeCrypto(address, amount); + async sendNativeCoin(address: string, amount: number): Promise { + return this.#client.sendNativeCoin(address, amount); } async sendToken(address: string, tokenName: Asset, amount: number): Promise { diff --git a/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts b/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts index dc81c13499..e20f7e3920 100644 --- a/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts +++ b/src/payment/models/payout/strategies/payout/__tests__/payout.facade.spec.ts @@ -1,7 +1,7 @@ import { mock } from 'jest-mock-extended'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; import { DexService } from 'src/payment/models/dex/services/dex.service'; -import { AssetCategory } from 'src/shared/models/asset/asset.entity'; +import { AssetType } from 'src/shared/models/asset/asset.entity'; import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; import { MailService } from 'src/shared/services/mail.service'; import { PayoutOrderRepository } from '../../../repositories/payout-order.repository'; @@ -10,28 +10,28 @@ import { PayoutBscService } from '../../../services/payout-bsc.service'; import { PayoutDeFiChainService } from '../../../services/payout-defichain.service'; import { PayoutEthereumService } from '../../../services/payout-ethereum.service'; import { BitcoinStrategy } from '../impl/bitcoin.strategy'; -import { BscCryptoStrategy } from '../impl/bsc-crypto.strategy'; +import { BscCoinStrategy } from '../impl/bsc-coin.strategy'; import { BscTokenStrategy } from '../impl/bsc-token.strategy'; -import { DeFiChainDfiStrategy } from '../impl/defichain-dfi.strategy'; +import { DeFiChainCoinStrategy } from '../impl/defichain-coin.strategy'; import { DeFiChainTokenStrategy } from '../impl/defichain-token.strategy'; -import { EthereumCryptoStrategy } from '../impl/ethereum-crypto.strategy'; +import { EthereumCoinStrategy } from '../impl/ethereum-coin.strategy'; import { EthereumTokenStrategy } from '../impl/ethereum-token.strategy'; import { PayoutStrategiesFacade, PayoutStrategyAlias } from '../payout.facade'; describe('PayoutStrategiesFacade', () => { let bitcoin: BitcoinStrategy; - let deFiChainDfi: DeFiChainDfiStrategy; + let deFiChainCoin: DeFiChainCoinStrategy; let deFiChainToken: DeFiChainTokenStrategy; - let ethereumCrypto: EthereumCryptoStrategy; + let ethereumCoin: EthereumCoinStrategy; let ethereumToken: EthereumTokenStrategy; - let bscCrypto: BscCryptoStrategy; + let bscCoin: BscCoinStrategy; let bscToken: BscTokenStrategy; let facade: PayoutStrategiesFacadeWrapper; beforeEach(() => { bitcoin = new BitcoinStrategy(mock(), mock(), mock()); - deFiChainDfi = new DeFiChainDfiStrategy( + deFiChainCoin = new DeFiChainCoinStrategy( mock(), mock(), mock(), @@ -42,18 +42,18 @@ describe('PayoutStrategiesFacade', () => { mock(), mock(), ); - ethereumCrypto = new EthereumCryptoStrategy(mock(), mock()); + ethereumCoin = new EthereumCoinStrategy(mock(), mock()); ethereumToken = new EthereumTokenStrategy(mock(), mock()); - bscCrypto = new BscCryptoStrategy(mock(), mock()); + bscCoin = new BscCoinStrategy(mock(), mock()); bscToken = new BscTokenStrategy(mock(), mock()); facade = new PayoutStrategiesFacadeWrapper( bitcoin, - bscCrypto, + bscCoin, bscToken, - deFiChainDfi, + deFiChainCoin, deFiChainToken, - ethereumCrypto, + ethereumCoin, ethereumToken, ); }); @@ -72,20 +72,20 @@ describe('PayoutStrategiesFacade', () => { expect(aliases.includes(PayoutStrategyAlias.BITCOIN)).toBe(true); expect(aliases.includes(PayoutStrategyAlias.BSC_TOKEN)).toBe(true); - expect(aliases.includes(PayoutStrategyAlias.BSC_CRYPTO)).toBe(true); - expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_DFI)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.BSC_COIN)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_COIN)).toBe(true); expect(aliases.includes(PayoutStrategyAlias.DEFICHAIN_TOKEN)).toBe(true); - expect(aliases.includes(PayoutStrategyAlias.ETHEREUM_CRYPTO)).toBe(true); + expect(aliases.includes(PayoutStrategyAlias.ETHEREUM_COIN)).toBe(true); expect(aliases.includes(PayoutStrategyAlias.ETHEREUM_TOKEN)).toBe(true); }); it('assigns proper payoutStrategies to aliases', () => { expect(facade.getStrategies().get(PayoutStrategyAlias.BITCOIN)).toBeInstanceOf(BitcoinStrategy); - expect(facade.getStrategies().get(PayoutStrategyAlias.BSC_CRYPTO)).toBeInstanceOf(BscCryptoStrategy); + expect(facade.getStrategies().get(PayoutStrategyAlias.BSC_COIN)).toBeInstanceOf(BscCoinStrategy); expect(facade.getStrategies().get(PayoutStrategyAlias.BSC_TOKEN)).toBeInstanceOf(BscTokenStrategy); - expect(facade.getStrategies().get(PayoutStrategyAlias.DEFICHAIN_DFI)).toBeInstanceOf(DeFiChainDfiStrategy); + expect(facade.getStrategies().get(PayoutStrategyAlias.DEFICHAIN_COIN)).toBeInstanceOf(DeFiChainCoinStrategy); expect(facade.getStrategies().get(PayoutStrategyAlias.DEFICHAIN_TOKEN)).toBeInstanceOf(DeFiChainTokenStrategy); - expect(facade.getStrategies().get(PayoutStrategyAlias.ETHEREUM_CRYPTO)).toBeInstanceOf(EthereumCryptoStrategy); + expect(facade.getStrategies().get(PayoutStrategyAlias.ETHEREUM_COIN)).toBeInstanceOf(EthereumCoinStrategy); expect(facade.getStrategies().get(PayoutStrategyAlias.ETHEREUM_TOKEN)).toBeInstanceOf(EthereumTokenStrategy); }); }); @@ -98,49 +98,49 @@ describe('PayoutStrategiesFacade', () => { expect(strategy).toBeInstanceOf(BitcoinStrategy); }); - it('gets BSC_CRYPTO strategy', () => { + it('gets BSC_COIN strategy', () => { const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.CRYPTO }), + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, type: AssetType.COIN }), ); - expect(strategy).toBeInstanceOf(BscCryptoStrategy); + expect(strategy).toBeInstanceOf(BscCoinStrategy); }); it('gets BSC_TOKEN strategy', () => { const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, category: AssetCategory.STOCK }), + createCustomAsset({ blockchain: Blockchain.BINANCE_SMART_CHAIN, type: AssetType.TOKEN }), ); expect(strategy).toBeInstanceOf(BscTokenStrategy); }); - it('gets DEFICHAIN_DFI strategy', () => { + it('gets DEFICHAIN_COIN strategy', () => { const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, dexName: 'DFI' }), + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, type: AssetType.COIN }), ); - expect(strategy).toBeInstanceOf(DeFiChainDfiStrategy); + expect(strategy).toBeInstanceOf(DeFiChainCoinStrategy); }); it('gets DEFICHAIN_TOKEN strategy for DEFICHAIN', () => { const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.DEFICHAIN, dexName: 'non-DFI' }), + createCustomAsset({ blockchain: Blockchain.DEFICHAIN, type: AssetType.TOKEN }), ); expect(strategy).toBeInstanceOf(DeFiChainTokenStrategy); }); - it('gets ETHEREUM_CRYPTO strategy', () => { + it('gets ETHEREUM_COIN strategy', () => { const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.CRYPTO }), + createCustomAsset({ blockchain: Blockchain.ETHEREUM, type: AssetType.COIN }), ); - expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + expect(strategy).toBeInstanceOf(EthereumCoinStrategy); }); it('gets ETHEREUM_TOKEN strategy', () => { const strategy = facade.getPayoutStrategy( - createCustomAsset({ blockchain: Blockchain.ETHEREUM, category: AssetCategory.STOCK }), + createCustomAsset({ blockchain: Blockchain.ETHEREUM, type: AssetType.TOKEN }), ); expect(strategy).toBeInstanceOf(EthereumTokenStrategy); @@ -162,10 +162,10 @@ describe('PayoutStrategiesFacade', () => { expect(strategyCrypto).toBeInstanceOf(BitcoinStrategy); }); - it('gets BSC_CRYPTO strategy', () => { - const strategyCrypto = facade.getPayoutStrategy(PayoutStrategyAlias.BSC_CRYPTO); + it('gets BSC_COIN strategy', () => { + const strategyCrypto = facade.getPayoutStrategy(PayoutStrategyAlias.BSC_COIN); - expect(strategyCrypto).toBeInstanceOf(BscCryptoStrategy); + expect(strategyCrypto).toBeInstanceOf(BscCoinStrategy); }); it('gets BSC_TOKEN strategy', () => { @@ -174,10 +174,10 @@ describe('PayoutStrategiesFacade', () => { expect(strategyCrypto).toBeInstanceOf(BscTokenStrategy); }); - it('gets DEFICHAIN_DFI strategy', () => { - const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_DFI); + it('gets DEFICHAIN_COIN strategy', () => { + const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.DEFICHAIN_COIN); - expect(strategy).toBeInstanceOf(DeFiChainDfiStrategy); + expect(strategy).toBeInstanceOf(DeFiChainCoinStrategy); }); it('gets DEFICHAIN_TOKEN strategy', () => { @@ -186,10 +186,10 @@ describe('PayoutStrategiesFacade', () => { expect(strategy).toBeInstanceOf(DeFiChainTokenStrategy); }); - it('gets ETHEREUM_CRYPTO strategy', () => { - const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_CRYPTO); + it('gets ETHEREUM_COIN strategy', () => { + const strategy = facade.getPayoutStrategy(PayoutStrategyAlias.ETHEREUM_COIN); - expect(strategy).toBeInstanceOf(EthereumCryptoStrategy); + expect(strategy).toBeInstanceOf(EthereumCoinStrategy); }); it('gets ETHEREUM_TOKEN strategy', () => { @@ -211,14 +211,14 @@ describe('PayoutStrategiesFacade', () => { class PayoutStrategiesFacadeWrapper extends PayoutStrategiesFacade { constructor( bitcoin: BitcoinStrategy, - bscCrypto: BscCryptoStrategy, + bscCoin: BscCoinStrategy, bscToken: BscTokenStrategy, - deFiChainDfi: DeFiChainDfiStrategy, + deFiChainCoin: DeFiChainCoinStrategy, deFiChainToken: DeFiChainTokenStrategy, - ethereumCrypto: EthereumCryptoStrategy, + ethereumCoin: EthereumCoinStrategy, ethereumToken: EthereumTokenStrategy, ) { - super(bitcoin, bscCrypto, bscToken, deFiChainDfi, deFiChainToken, ethereumCrypto, ethereumToken); + super(bitcoin, bscCoin, bscToken, deFiChainCoin, deFiChainToken, ethereumCoin, ethereumToken); } getStrategies() { diff --git a/src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts b/src/payment/models/payout/strategies/payout/impl/bsc-coin.strategy.ts similarity index 80% rename from src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts rename to src/payment/models/payout/strategies/payout/impl/bsc-coin.strategy.ts index 45828fa2f4..794e8709d7 100644 --- a/src/payment/models/payout/strategies/payout/impl/bsc-crypto.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/bsc-coin.strategy.ts @@ -5,12 +5,12 @@ import { PayoutBscService } from '../../../services/payout-bsc.service'; import { EvmStrategy } from './base/evm.strategy'; @Injectable() -export class BscCryptoStrategy extends EvmStrategy { +export class BscCoinStrategy extends EvmStrategy { constructor(protected readonly bscService: PayoutBscService, payoutOrderRepo: PayoutOrderRepository) { super(bscService, payoutOrderRepo); } protected dispatchPayout(order: PayoutOrder): Promise { - return this.bscService.sendNativeCrypto(order.destinationAddress, order.amount); + return this.bscService.sendNativeCoin(order.destinationAddress, order.amount); } } diff --git a/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts b/src/payment/models/payout/strategies/payout/impl/defichain-coin.strategy.ts similarity index 96% rename from src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts rename to src/payment/models/payout/strategies/payout/impl/defichain-coin.strategy.ts index e50357d11c..a8879c823d 100644 --- a/src/payment/models/payout/strategies/payout/impl/defichain-dfi.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/defichain-coin.strategy.ts @@ -7,7 +7,7 @@ import { PayoutDeFiChainService } from '../../../services/payout-defichain.servi import { JellyfishStrategy } from './base/jellyfish.strategy'; @Injectable() -export class DeFiChainDfiStrategy extends JellyfishStrategy { +export class DeFiChainCoinStrategy extends JellyfishStrategy { constructor( mailService: MailService, protected readonly deFiChainService: PayoutDeFiChainService, diff --git a/src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts b/src/payment/models/payout/strategies/payout/impl/ethereum-coin.strategy.ts similarity index 79% rename from src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts rename to src/payment/models/payout/strategies/payout/impl/ethereum-coin.strategy.ts index f3734499ce..8675ca85d0 100644 --- a/src/payment/models/payout/strategies/payout/impl/ethereum-crypto.strategy.ts +++ b/src/payment/models/payout/strategies/payout/impl/ethereum-coin.strategy.ts @@ -5,12 +5,12 @@ import { PayoutEthereumService } from '../../../services/payout-ethereum.service import { EvmStrategy } from './base/evm.strategy'; @Injectable() -export class EthereumCryptoStrategy extends EvmStrategy { +export class EthereumCoinStrategy extends EvmStrategy { constructor(protected readonly ethereumService: PayoutEthereumService, payoutOrderRepo: PayoutOrderRepository) { super(ethereumService, payoutOrderRepo); } protected dispatchPayout(order: PayoutOrder): Promise { - return this.ethereumService.sendNativeCrypto(order.destinationAddress, order.amount); + return this.ethereumService.sendNativeCoin(order.destinationAddress, order.amount); } } diff --git a/src/payment/models/payout/strategies/payout/payout.facade.ts b/src/payment/models/payout/strategies/payout/payout.facade.ts index 738dc437be..44114f7af7 100644 --- a/src/payment/models/payout/strategies/payout/payout.facade.ts +++ b/src/payment/models/payout/strategies/payout/payout.facade.ts @@ -1,22 +1,22 @@ import { Injectable } from '@nestjs/common'; import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { Asset, AssetCategory } from 'src/shared/models/asset/asset.entity'; +import { Asset, AssetType } from 'src/shared/models/asset/asset.entity'; import { PayoutStrategy } from './impl/base/payout.strategy'; import { BitcoinStrategy } from './impl/bitcoin.strategy'; -import { BscCryptoStrategy } from './impl/bsc-crypto.strategy'; +import { BscCoinStrategy } from './impl/bsc-coin.strategy'; import { BscTokenStrategy } from './impl/bsc-token.strategy'; -import { DeFiChainDfiStrategy } from './impl/defichain-dfi.strategy'; +import { DeFiChainCoinStrategy } from './impl/defichain-coin.strategy'; import { DeFiChainTokenStrategy } from './impl/defichain-token.strategy'; -import { EthereumCryptoStrategy } from './impl/ethereum-crypto.strategy'; +import { EthereumCoinStrategy } from './impl/ethereum-coin.strategy'; import { EthereumTokenStrategy } from './impl/ethereum-token.strategy'; enum Alias { BITCOIN = 'Bitcoin', - BSC_CRYPTO = 'BscCrypto', + BSC_COIN = 'BscCoin', BSC_TOKEN = 'BscToken', - DEFICHAIN_DFI = 'DeFiChainDFI', + DEFICHAIN_COIN = 'DeFiChainCoin', DEFICHAIN_TOKEN = 'DeFiChainToken', - ETHEREUM_CRYPTO = 'EthereumCrypto', + ETHEREUM_COIN = 'EthereumCoin', ETHEREUM_TOKEN = 'EthereumToken', } @@ -28,19 +28,19 @@ export class PayoutStrategiesFacade { constructor( bitcoin: BitcoinStrategy, - bscCrypto: BscCryptoStrategy, + bscCoin: BscCoinStrategy, bscToken: BscTokenStrategy, - deFiChainDfi: DeFiChainDfiStrategy, + deFiChainCoin: DeFiChainCoinStrategy, deFiChainToken: DeFiChainTokenStrategy, - ethereumCrypto: EthereumCryptoStrategy, + ethereumCoin: EthereumCoinStrategy, ethereumToken: EthereumTokenStrategy, ) { this.strategies.set(Alias.BITCOIN, bitcoin); - this.strategies.set(Alias.BSC_CRYPTO, bscCrypto); + this.strategies.set(Alias.BSC_COIN, bscCoin); this.strategies.set(Alias.BSC_TOKEN, bscToken); - this.strategies.set(Alias.DEFICHAIN_DFI, deFiChainDfi); + this.strategies.set(Alias.DEFICHAIN_COIN, deFiChainCoin); this.strategies.set(Alias.DEFICHAIN_TOKEN, deFiChainToken); - this.strategies.set(Alias.ETHEREUM_CRYPTO, ethereumCrypto); + this.strategies.set(Alias.ETHEREUM_COIN, ethereumCoin); this.strategies.set(Alias.ETHEREUM_TOKEN, ethereumToken); } @@ -49,26 +49,20 @@ export class PayoutStrategiesFacade { } getPayoutStrategyAlias(asset: Asset): Alias { - const { blockchain, dexName: assetName, category: assetCategory } = asset; + const { blockchain, type: assetType } = asset; if (blockchain === Blockchain.BITCOIN) return Alias.BITCOIN; if (blockchain === Blockchain.BINANCE_SMART_CHAIN) { - if (assetCategory === AssetCategory.CRYPTO) return Alias.BSC_CRYPTO; - if (assetCategory === AssetCategory.STOCK) return Alias.BSC_TOKEN; + return assetType === AssetType.COIN ? Alias.BSC_COIN : Alias.BSC_TOKEN; } if (blockchain === Blockchain.DEFICHAIN) { - if (assetName === 'DFI') { - return Alias.DEFICHAIN_DFI; - } else { - return Alias.DEFICHAIN_TOKEN; - } + return assetType === AssetType.COIN ? Alias.DEFICHAIN_COIN : Alias.DEFICHAIN_TOKEN; } if (blockchain === Blockchain.ETHEREUM) { - if (assetCategory === AssetCategory.CRYPTO) return Alias.ETHEREUM_CRYPTO; - if (assetCategory === AssetCategory.STOCK) return Alias.ETHEREUM_TOKEN; + return assetType === AssetType.COIN ? Alias.ETHEREUM_COIN : Alias.ETHEREUM_TOKEN; } } diff --git a/src/shared/models/asset/__mocks__/asset.entity.mock.ts b/src/shared/models/asset/__mocks__/asset.entity.mock.ts index 305cc294a5..df8276d56a 100644 --- a/src/shared/models/asset/__mocks__/asset.entity.mock.ts +++ b/src/shared/models/asset/__mocks__/asset.entity.mock.ts @@ -1,12 +1,12 @@ import { Blockchain } from 'src/blockchain/shared/enums/blockchain.enum'; -import { Asset, AssetCategory } from '../asset.entity'; +import { Asset, AssetCategory, AssetType } from '../asset.entity'; export function createDefaultAsset(): Asset { return createCustomAsset({}); } export function createCustomAsset(customValues: Partial): Asset { - const { name, dexName, blockchain, category } = customValues; + const { name, dexName, blockchain, category, type } = customValues; const keys = Object.keys(customValues); const entity = new Asset(); @@ -15,6 +15,7 @@ export function createCustomAsset(customValues: Partial): Asset { entity.dexName = keys.includes('dexName') ? dexName : 'dTSLA'; entity.blockchain = keys.includes('blockchain') ? blockchain : Blockchain.DEFICHAIN; entity.category = keys.includes('category') ? category : AssetCategory.CRYPTO; + entity.type = keys.includes('type') ? type : AssetType.COIN; return entity; } diff --git a/src/shared/models/asset/asset.entity.ts b/src/shared/models/asset/asset.entity.ts index 39d8f1879a..ed12599f05 100644 --- a/src/shared/models/asset/asset.entity.ts +++ b/src/shared/models/asset/asset.entity.ts @@ -4,8 +4,7 @@ import { IEntity } from '../entity'; export enum AssetType { COIN = 'Coin', - DCT = 'DCT', - DAT = 'DAT', + TOKEN = 'Token', } export enum AssetCategory {