diff --git a/apps/whale-api/src/e2e.defid.module.ts b/apps/whale-api/src/e2e.defid.module.ts new file mode 100644 index 0000000000..a2b115a8be --- /dev/null +++ b/apps/whale-api/src/e2e.defid.module.ts @@ -0,0 +1,687 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +/* eslint-disable @typescript-eslint/no-misused-promises */ +/* eslint-disable @typescript-eslint/restrict-template-expressions */ + +import { fetch } from 'cross-fetch' +import { v4 as uuidv4 } from 'uuid' +import fs from 'fs' +import { ChildProcess, spawn } from 'child_process' +import { RegTestFoundationKeys } from '@defichain/jellyfish-network' +import { ApiPagedResponse } from './module.api/_core/api.paged.response' + +import { AddressToken, AddressHistory } from '@defichain/whale-api-client/dist/api/address' +import { Block } from './module.model/block' +import { MasternodeData } from '@defichain/whale-api-client/dist/api/masternodes' +import { + AllSwappableTokensResult, + BestSwapPathResult, DexPricesResult, + PoolPairData, + PoolSwapAggregatedData, + PoolSwapData, + SwapPathsResult +} from '@defichain/whale-api-client/dist/api/poolpairs' +import { GovernanceProposal, ProposalVotesResult } from '@defichain/whale-api-client/dist/api/governance' +import { LoanVaultActive, LoanVaultLiquidated } from '@defichain/whale-api-client/dist/api/loan' +import { MasternodeType } from '@defichain/jellyfish-api-core/dist/category/governance' +import { Oracle } from './module.model/oracle' +import { OraclePriceAggregated } from './module.model/oracle.price.aggregated' +import { OraclePriceFeed } from './module.model/oracle.price.feed' +import { OraclePriceActive } from './module.model/oracle.price.active' +import { PriceTicker } from './module.model/price.ticker' +import { PriceFeedInterval, PriceOracle } from '@defichain/whale-api-client/dist/api/prices' +import { RawTransaction } from '@defichain/jellyfish-api-core/dist/category/rawtx' +import { ScriptActivity } from './module.model/script.activity' +import { ScriptAggregation } from './module.model/script.aggregation' +import { ScriptUnspent } from './module.model/script.unspent' +import { BurnData, RewardDistributionData, StatsData, SupplyData } from '@defichain/whale-api-client/dist/api/stats' +import { TokenData } from '@defichain/whale-api-client/dist/api/tokens' +import { Transaction } from './module.model/transaction' +import { TransactionVin } from './module.model/transaction.vin' +import { TransactionVout } from './module.model/transaction.vout' +import { DeFiDRpcError, waitForCondition } from '@defichain/testcontainers' +import { isSHA256Hash, parseHeight } from './module.api/block.controller' + +const SPAWNING_TIME = 180_000 + +export interface OceanListQuery { + size: number + next?: string +} + +export interface OceanRawTxQuery { + verbose: boolean +} + +export interface OceanProposalQuery { + masternode?: MasternodeType | string + cycle?: number + all?: boolean + query?: OceanListQuery +} + +class DefidOceanApi { + endpoint = 'http://127.0.0.1:3002' + + async get (path: string): Promise { + const res = await fetch(`${this.endpoint}${path}`, { + method: 'GET' + }) + return await res.json() + } + + async post (path: string, data?: any): Promise { + const res = await fetch(`${this.endpoint}${path}`, { + method: 'POST', + body: JSON.stringify(data) + }) + return await res.json() + } +} + +export class DefidOceanController { + protected readonly api: DefidOceanApi = new DefidOceanApi() +} + +export class DAddressController extends DefidOceanController { + async getAccountHistory (address: string, height: number, txno: number): Promise { + return await this.api.get(`/address/${address}/history/${height}/${txno}`) + } + + async listAccountHistory (address: string, query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/address/${address}/history?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/address/${address}/history?size=${query.size}`) + } + + async getBalance (address: string): Promise { + return await this.api.get(`/address/${address}/balance`) + } + + async getAggregation (address: string): Promise { + return await this.api.get(`/address/${address}/aggregation`) + } + + async listTokens (address: string, query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/address/${address}/tokens?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/address/${address}/tokens?size=${query.size}`) + } + + async listVaults (address: string, query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/address/${address}/vaults?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/address/${address}/vaults?size=${query.size}`) + } + + async listTransactions (address: string, query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/address/${address}/transactions?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/address/${address}/transactions?size=${query.size}`) + } + + async listTransactionsUnspent (address: string, query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/address/${address}/transactions/unspent?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/address/${address}/transactions/unspent?size=${query.size}`) + } +} + +export class DBlockController extends DefidOceanController { + async list (query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + const next = parseHeight(query.next) + return await this.api.get(`/blocks?size=${query.size}&next=${next}`) + } + return await this.api.get(`/blocks?size=${query.size}`) + } + + async get (hashOrHeight: string): Promise { + const height = parseHeight(hashOrHeight) + if (height !== undefined) { + return await this.api.get(`/blocks/${height}`) + } + if (isSHA256Hash(hashOrHeight)) { + return await this.api.get(`/blocks/${hashOrHeight}`) + } + } + + async getTransactions (hash: string, query: OceanListQuery = { size: 30 }): Promise> { + if (!isSHA256Hash(hash)) { + return ApiPagedResponse.empty() + } + if (query.next !== undefined) { + return await this.api.get(`/blocks/${hash}/transactions?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/blocks/${hash}/transactions?size=${query.size}`) + } + + async getHighest (): Promise { + return await this.api.get('/blocks/highest') + } +} + +export class DFeeController extends DefidOceanController { + async estimate (): Promise { + return await this.api.get('/fee/estimate') + } +} + +export class DGovernanceController extends DefidOceanController { + async listProposals (): Promise> { + return await this.api.get('/governance/proposals') + } + + async getProposal (id: string): Promise { + return await this.api.get(`/governance/proposals/${id}`) + } + + async listProposalVotes ( + id: string, + masternode = MasternodeType.MINE, + cycle = 0, + all = false, + query: OceanListQuery = { size: 30 } + ): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/governance/proposals/${id}/votes?masternode=${masternode}&cycle=${cycle}&all=${all}&size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/governance/proposals/${id}/votes?masternode=${masternode}&cycle=${cycle}&all=${all}&size=${query.size}`) + } +} + +export class DMasternodeController extends DefidOceanController { + async list (query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/masternodes?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/masternodes?size=${query.size}`) + } + + async get (id: string): Promise { + return await this.api.get(`/masternodes/${id}`) + } +} + +export class DOracleController extends DefidOceanController { + async list (query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/oracles?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/oracles?size=${query.size}`) + } + + async getPriceFeed (id: string, key: string): Promise> { + return await this.api.get(`/oracles/${id}/${key}/feed`) + } + + async getOracleByAddress (address: string): Promise { + return await this.api.get(`/oracles/${address}`) + } +} + +export class DPoolPairController extends DefidOceanController { + async list (query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/poolpairs?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/poolpairs?size=${query.size}`) + } + + async get (id: string): Promise { + return await this.api.get(`/poolpairs/${id}`) + } + + async listPoolSwaps (id: string, query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/poolpairs/${id}/swaps?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/poolpairs/${id}/swaps?size=${query.size}`) + } + + async listPoolSwapsVerbose (id: string, query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/poolpairs/${id}/swaps/verbose?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/poolpairs/${id}/swaps/verbose?size=${query.size}`) + } + + async listPoolSwapsAggregate (id: string, interval: number, query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/poolpairs/${id}/swaps/aggregate/${interval}?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/poolpairs/${id}/swaps/aggregate/${interval}?size=${query.size}`) + } + + async listSwappableTokens (id: string): Promise { + return await this.api.get(`/poolpairs/paths/swappable/${id}`) + } + + async listPaths (fromTokenId: string, toTokenId: string): Promise { + return await this.api.get(`/poolpairs/paths/from/${fromTokenId}/to/${toTokenId}`) + } + + async getBestPath (fromTokenId: string, toTokenId: string): Promise { + return await this.api.get(`/poolpairs/paths/best/from/${fromTokenId}/to/${toTokenId}`) + } + + async listDexPrices (denomination: string): Promise { + return await this.api.get(`/poolpairs/dexprices?denomination=${denomination}`) + } +} + +export class DPriceController extends DefidOceanController { + async list (query: OceanListQuery = { size: 30 }): Promise> { + if (query.next !== undefined) { + return await this.api.get(`/prices?size=${query.size}&next=${query.next}`) + } + return await this.api.get(`/prices?size=${query.size}`) + } + + async get (id: string): Promise { + return await this.api.get(`/prices/${id}`) + } + + async getFeed (id: string): Promise> { + return await this.api.get(`/prices/${id}/feed`) + } + + async getFeedActive (id: string): Promise> { + return await this.api.get(`/prices/${id}/feed/active`) + } + + async getFeedWithInterval (id: string, interval: number): Promise> { + return await this.api.get(`/prices/${id}/feed/interval/${interval}`) + } + + async listPriceOracles (id: string): Promise> { + return await this.api.get(`/prices/${id}/oracles`) + } +} + +export class DRawTxController extends DefidOceanController { + async send (): Promise { + return await this.api.post('/rawtx/send') + } + + async test (): Promise { + return await this.api.get('/rawtx/test') + } + + async get (id: string, verbose = false): Promise { + return await this.api.get(`/rawtx/${id}?verbose=${verbose}`) + } +} + +export class DStatsController extends DefidOceanController { + async get (): Promise { + return await this.api.get('/stats') + } + + async getSupply (): Promise { + return await this.api.get('/stats/supply') + } + + async getBurn (): Promise { + return await this.api.get('/stats/burn') + } + + async getRewardDistribution (): Promise { + return await this.api.get('/stats/reward/distribution') + } +} + +export class DTokenController extends DefidOceanController { + async list (): Promise> { + return await this.api.get('/tokens') + } + + async get (id: string): Promise { + return await this.api.get(`/tokens/${id}`) + } +} + +export class DTransactionController extends DefidOceanController { + async get (id: string): Promise { + return await this.api.get(`/transactions/${id}`) + } + + async getVins (id: string): Promise> { + return await this.api.get(`/transactions/${id}/vins`) + } + + async getVouts (id: string): Promise> { + return await this.api.get(`/transactions/${id}/vouts`) + } +} + +export class DefidOcean { + constructor ( + readonly addressController: DAddressController, + readonly blockController: DBlockController, + readonly feeController: DFeeController, + readonly governanceController: DGovernanceController, + readonly masternodeController: DMasternodeController, + readonly oracleController: DOracleController, + readonly poolPairController: DPoolPairController, + readonly priceController: DPriceController, + readonly rawTxController: DRawTxController, + readonly statsController: DStatsController, + readonly transactionController: DTransactionController, + readonly tokenController: DTokenController + ) { + } +} + +export class DefidRpc { + rpcUrl = 'http://test:test@127.0.0.1:19554' + + getCachedRpcUrl (): string { + return this.rpcUrl + } + + async call (method: string, params: any = []): Promise { + const body = JSON.stringify({ + jsonrpc: '1.0', + id: Math.floor(Math.random() * 100000000000000), + method: method, + params: params + }) + + const text = await this.post(body) + const { + result, + error + } = JSON.parse(text) + + if (error !== undefined && error !== null) { + throw new DeFiDRpcError(error) + } + + return result + } + + async post (body: string): Promise { + const response = await fetch(this.rpcUrl, { + method: 'POST', + body: body + }) + return await response.text() + } + + async generate ( + nblocks: number, + address?: string | undefined, + maxTries: number = 1000000 + ): Promise { + if (address === undefined) { + address = await this.call('getnewaddress') + } + for (let minted = 0, tries = 0; minted < nblocks && tries < maxTries; tries++) { + const result = await this.call('generatetoaddress', [1, address, 1]) + if (result === 1) { + minted += 1 + } + } + } + + async waitForBlockHeight (height: number, timeout = 590000): Promise { + return await waitForCondition(async () => { + const count = await this.getBlockCount() + if (count > height) { + return true + } + await this.generate(1) + return false + }, timeout, 100, 'waitForBlockHeight') + } + + async blockHeight (height: number, timeout: number = 590000): Promise { + return await waitForCondition(async () => { + const count = await this.getBlockCount() + if (count > height) { + return true + } + await this.generate(1) + return false + }, timeout, 100, 'waitForBlockHeight') + } + + async waitForWalletCoinbaseMaturity (timeout: number = 180000, mockTime: boolean = true): Promise { + if (!mockTime) { + return await this.blockHeight(100, timeout) + } + + let fakeTime: number = 1579045065 + await this.call('setmocktime', [fakeTime]) + + const intervalId = setInterval(() => { + fakeTime += 3 + void this.call('setmocktime', [fakeTime]) + }, 200) + + await this.blockHeight(100, timeout) + + clearInterval(intervalId) + await this.call('setmocktime', [0]) + } + + async waitForWalletBalanceGTE (balance: number, timeout: number = 300000): Promise { + return await waitForCondition(async () => { + const getbalance = await this.call('getbalance') + if (getbalance >= balance) { + return true + } + await this.generate(1) + return false + }, timeout, 100, 'waitForWalletBalanceGTE') + } + + async getNewAddress (label: string = '', addressType: 'legacy' | 'p2sh-segwit' | 'bech32' | 'eth' | string = 'bech32'): Promise { + return await this.call('getnewaddress', [label, addressType]) + } + + async getBlockCount (): Promise { + return await this.call('getblockcount', []) + } + + async createToken (symbol: string, options?: CreateTokenOptions): Promise { + const metadata = { + symbol, + name: options?.name ?? symbol, + isDAT: options?.isDAT ?? true, + mintable: options?.mintable ?? true, + tradeable: options?.tradeable ?? true, + collateralAddress: options?.collateralAddress ?? await this.getNewAddress() + } + + await this.waitForWalletBalanceGTE(101) + await this.call('create', [metadata]) + await this.generate(1) + + const res = await this.call('gettoken', [symbol]) + return Number.parseInt(Object.keys(res)[0]) + } + + async createPoolPair (aToken: string, bToken: string, options?: CreatePoolPairOptions): Promise { + const metadata = { + tokenA: aToken, + tokenB: bToken, + commission: options?.commission ?? 0, + status: options?.status ?? true, + ownerAddress: options?.ownerAddress ?? await this.getNewAddress() + } + const txid = await this.call('createpoolpair', [metadata, options?.utxos]) + await this.generate(1) + return txid + } +} + +export class DefidBin { + tmpDir: string = `/tmp/${uuidv4()}` + binary: ChildProcess | null = null + rpc = new DefidRpc() + ocean = new DefidOcean( + new DAddressController(), + new DBlockController(), + new DFeeController(), + new DGovernanceController(), + new DMasternodeController(), + new DOracleController(), + new DPoolPairController(), + new DPriceController(), + new DRawTxController(), + new DStatsController(), + new DTransactionController(), + new DTokenController() + ) + + async start (): Promise { + fs.mkdirSync(this.tmpDir) + + if (process.env.DEFID === undefined) { + throw new Error('`process.env.DEFID` is required') + } + + const args = [ + `-datadir=${this.tmpDir}`, + '-regtest', + '-printtoconsole', + '-gen=0', + '-rpcuser=test', + '-rpcpassword=test', + '-jellyfish_regtest', + '-logtimemicros', + '-logthreadnames', + '-debug', + `-masternode_operator=${RegTestFoundationKeys[1].operator.address}`, + '-dummypos=0', + '-txnotokens=0', + '-logtimemicros', + '-txindex=1', + '-acindex=1', + '-oceanarchive' + ] + + const extraArgs = [ + '-amkheight=0', + '-bayfrontheight=1', + '-bayfrontgardensheight=2', + '-clarkequayheight=3', + '-dakotaheight=4', + '-dakotacrescentheight=5', + '-eunosheight=6', + '-eunospayaheight=7', + '-fortcanningheight=8', + '-fortcanningmuseumheight=9', + '-fortcanninghillheight=10', + '-fortcanningroadheight=11', + '-fortcanningcrunchheight=12', + '-fortcanningspringheight=13', + '-fortcanninggreatworldheight=14', + '-fortcanningepilogueheight=15', + '-grandcentralheight=16', + '-grandcentralepilogueheight=17', + '-metachainheight=18' + ] + + const binary = spawn(process.env.DEFID, args.concat(extraArgs)) + + binary.on('error', err => { + if ((err as any).errno === 'ENOENT') { + console.error('\x1b[31mMissing Defid binary.\nPlease compile the Defid\x1b[0m') + } else { + console.error(err) + } + process.exit(1) + }) + + const logs: string[] = [] + + await new Promise((resolve, reject) => { + const timer = setTimeout(() => { + console.error('\x1b[31m Failed to start Defid node.\x1b[0m') + console.error(logs.map(chunk => chunk.toString()).join('\n')) + process.exit(1) + }, SPAWNING_TIME - 20_000) + + const onData = async (chunk: any) => { + logs.push(chunk) + + /* eslint-disable-next-line @typescript-eslint/strict-boolean-expressions */ + if (chunk.toString().match(/addcon thread start/)) { + // wait for ocean + await new Promise((resolve) => setTimeout(resolve, 1000)) + + try { + // TODO(canonbrother): blockController.get(0) + const res = await this.ocean.blockController.list({ size: 1 }) + console.log('[DefidBin.start()] blockController.list res: ', res) + } catch (err) { + console.log('[DefidBin.start()] blockController.get err: ', err) + } + + clearTimeout(timer) + + binary.stderr.off('data', onData) + binary.stdout.off('data', onData) + + await this.rpc.call('importprivkey', [RegTestFoundationKeys[1].owner.privKey]) + await this.rpc.call('importprivkey', [RegTestFoundationKeys[1].operator.privKey]) + + // setgov + // generate(2) + + resolve() + } + } + + binary.stderr.on('data', onData) + binary.stdout.on('data', onData) + }) + + this.binary = binary + } + + async stop (): Promise { + const interval = setInterval(() => { + if (this.binary?.pid !== undefined && !this.isRunning(this.binary?.pid)) { + clearInterval(interval) + fs.rmdirSync(this.tmpDir, { recursive: true }) + } + }, 500) + this.binary?.kill() + } + + private isRunning (pid: number): boolean { + try { + return process.kill(pid, 0) + } catch (err: any) { + return err.code === 'EPERM' + } + } +} + +interface CreateTokenOptions { + name?: string + isDAT?: boolean + mintable?: boolean + tradeable?: boolean + collateralAddress?: string +} + +interface CreatePoolPairOptions { + commission?: number + status?: boolean + ownerAddress?: string + utxos?: UTXO[] +} + +interface UTXO { + txid: string + vout: number +} diff --git a/apps/whale-api/src/e2e.module.ts b/apps/whale-api/src/e2e.module.ts index 2473393e98..eb0c278601 100644 --- a/apps/whale-api/src/e2e.module.ts +++ b/apps/whale-api/src/e2e.module.ts @@ -10,6 +10,7 @@ import waitForExpect from 'wait-for-expect' import { addressToHid } from './module.api/address.controller' import { ScriptAggregationMapper } from './module.model/script.aggregation' import { TestingGroup } from '@defichain/jellyfish-testing' +import { DefidBin } from './e2e.defid.module' /** * Configures an end-to-end testing app integrated with all modules. @@ -46,7 +47,7 @@ export async function stopTestingApp (container: MasterNodeRegTestContainer | Te } finally { await new Promise((resolve) => { // Wait 2000ms between indexer cycle time to prevent database error - setTimeout(_ => resolve(0), 500) + setTimeout((_: any) => resolve(0), 500) }) if (container instanceof MasterNodeRegTestContainer) { @@ -82,12 +83,20 @@ export async function waitForIndexedHeightLatest (app: NestFastifyApplication, c * @param {number} height to wait for * @param {number} [timeout=30000] */ -export async function waitForIndexedHeight (app: NestFastifyApplication, height: number, timeout: number = 30000): Promise { - const blockMapper = app.get(BlockMapper) - await waitForExpect(async () => { - const block = await blockMapper.getHighest() - await expect(block?.height).toBeGreaterThan(height) - }, timeout) +export async function waitForIndexedHeight (app: NestFastifyApplication | DefidBin, height: number, timeout: number = 30000): Promise { + if (app instanceof DefidBin) { + await waitForExpect(async () => { + const block = await app.ocean.blockController.getHighest() + expect(block?.height).toBeGreaterThan(height) + await app.rpc.generate(1) + }, timeout) + } else { + const blockMapper = app.get(BlockMapper) + await waitForExpect(async () => { + const block = await blockMapper.getHighest() + expect(block?.height).toBeGreaterThan(height) + }, timeout) + } await new Promise((resolve) => setTimeout(resolve, 1000)) } @@ -105,7 +114,11 @@ export async function waitForIndexedTimestamp (container: MasterNodeRegTestConta }, timeout) } -export async function waitForAddressTxCount (app: NestFastifyApplication, address: string, txCount: number, timeout: number = 15000): Promise { +// TODO(): handle DefidBin +export async function waitForAddressTxCount (app: NestFastifyApplication | DefidBin, address: string, txCount: number, timeout: number = 15000): Promise { + if (app instanceof DefidBin) { + return + } const hid = addressToHid('regtest', address) const aggregationMapper = app.get(ScriptAggregationMapper) await waitForExpect(async () => { diff --git a/apps/whale-api/src/module.api/address.controller.e2e.ts b/apps/whale-api/src/module.api/address.controller.e2e.ts index d9c80b7727..9f9b2a4c97 100644 --- a/apps/whale-api/src/module.api/address.controller.e2e.ts +++ b/apps/whale-api/src/module.api/address.controller.e2e.ts @@ -8,10 +8,11 @@ import { Testing } from '@defichain/jellyfish-testing' import { ForbiddenException } from '@nestjs/common' import BigNumber from 'bignumber.js' import { RegTestFoundationKeys } from '@defichain/jellyfish-network' +import { DAddressController, DefidBin } from '../e2e.defid.module' const container = new MasterNodeRegTestContainer() -let app: NestFastifyApplication -let controller: AddressController +let app: NestFastifyApplication | DefidBin +let controller: AddressController | DAddressController const testing = Testing.create(container) let colAddr: string let usdcAddr: string @@ -149,7 +150,11 @@ describe('listAccountHistory', () => { await testing.generate(1) app = await createTestingApp(container) - controller = app.get(AddressController) + if (app instanceof DefidBin) { + controller = app.addressController + } else { + controller = app.get(AddressController) + } await testing.generate(1) @@ -398,7 +403,11 @@ describe('getAccount', () => { await testing.generate(1) app = await createTestingApp(container) - controller = app.get(AddressController) + if (app instanceof DefidBin) { + controller = app.addressController + } else { + controller = app.get(AddressController) + } await testing.generate(1) }) @@ -474,7 +483,11 @@ describe('getBalance', () => { await container.waitForWalletBalanceGTE(100) app = await createTestingApp(container) - controller = app.get(AddressController) + if (app instanceof DefidBin) { + controller = app.addressController + } else { + controller = app.get(AddressController) + } await waitForIndexedHeight(app, 100) }) @@ -543,7 +556,11 @@ describe('getAggregation', () => { await container.waitForWalletBalanceGTE(100) app = await createTestingApp(container) - controller = app.get(AddressController) + if (app instanceof DefidBin) { + controller = app.addressController + } else { + controller = app.get(AddressController) + } await waitForIndexedHeight(app, 100) }) @@ -599,7 +616,11 @@ describe('listTransactions', () => { await container.waitForWalletBalanceGTE(100) app = await createTestingApp(container) - controller = app.get(AddressController) + if (app instanceof DefidBin) { + controller = app.addressController + } else { + controller = app.get(AddressController) + } await waitForIndexedHeight(app, 100) @@ -759,7 +780,11 @@ describe('listTransactionsUnspent', () => { await container.waitForWalletBalanceGTE(100) app = await createTestingApp(container) - controller = app.get(AddressController) + if (app instanceof DefidBin) { + controller = app.addressController + } else { + controller = app.get(AddressController) + } await waitForIndexedHeight(app, 100) @@ -988,7 +1013,11 @@ describe('listTokens', () => { await container.waitForWalletBalanceGTE(100) app = await createTestingApp(container) - controller = app.get(AddressController) + if (app instanceof DefidBin) { + controller = app.addressController + } else { + controller = app.get(AddressController) + } await waitForIndexedHeight(app, 100) diff --git a/apps/whale-api/src/module.api/block.controller.e2e.ts b/apps/whale-api/src/module.api/block.controller.e2e.ts index 616a5dcd44..3d6ea5916f 100644 --- a/apps/whale-api/src/module.api/block.controller.e2e.ts +++ b/apps/whale-api/src/module.api/block.controller.e2e.ts @@ -3,21 +3,33 @@ import { MasterNodeRegTestContainer } from '@defichain/testcontainers' import { NestFastifyApplication } from '@nestjs/platform-fastify' import { createTestingApp, stopTestingApp, waitForIndexedHeight } from '../e2e.module' import { JsonRpcClient } from '@defichain/jellyfish-api-jsonrpc' +import { DBlockController, DefidBin, DefidRpc } from '../e2e.defid.module' -const container = new MasterNodeRegTestContainer() -let app: NestFastifyApplication -let controller: BlockController +let app: NestFastifyApplication | DefidBin +let container: MasterNodeRegTestContainer | DefidRpc +let controller: BlockController | DBlockController let client: JsonRpcClient beforeAll(async () => { - await container.start() - await container.waitForBlockHeight(101) - - app = await createTestingApp(container) - - await waitForIndexedHeight(app, 100) - controller = app.get(BlockController) - client = new JsonRpcClient(await container.getCachedRpcUrl()) + if (process.env.DEFID !== undefined) { + app = new DefidBin() + await app.start() + container = app.rpc + controller = app.ocean.blockController + await container.waitForBlockHeight(101) + // await waitForIndexedHeight(app, 100) + client = new JsonRpcClient(container.getCachedRpcUrl()) + } else { + container = new MasterNodeRegTestContainer() + await container.start() + await container.waitForBlockHeight(101) + + app = await createTestingApp(container) + + await waitForIndexedHeight(app, 100) + controller = app.get(BlockController) + client = new JsonRpcClient(await container.getCachedRpcUrl()) + } const address = await container.getNewAddress() for (let i = 0; i < 4; i += 1) { @@ -29,7 +41,11 @@ beforeAll(async () => { }) afterAll(async () => { - await stopTestingApp(container, app) + if (process.env.DEFID !== undefined) { + await (app as DefidBin).stop() + return + } + await stopTestingApp(container as MasterNodeRegTestContainer, app as NestFastifyApplication) }) describe('get', () => { diff --git a/apps/whale-api/src/module.api/fee.controller.e2e.ts b/apps/whale-api/src/module.api/fee.controller.e2e.ts index fc408a64fb..a945428343 100644 --- a/apps/whale-api/src/module.api/fee.controller.e2e.ts +++ b/apps/whale-api/src/module.api/fee.controller.e2e.ts @@ -3,24 +3,39 @@ import { MasterNodeRegTestContainer } from '@defichain/testcontainers' import { NestFastifyApplication } from '@nestjs/platform-fastify' import { createTestingApp, stopTestingApp } from '../e2e.module' import { FeeController } from './fee.controller' +import { DefidBin, DefidRpc, DFeeController } from '../e2e.defid.module' -const container = new MasterNodeRegTestContainer() -let app: NestFastifyApplication -let controller: FeeController +let container: MasterNodeRegTestContainer | DefidRpc +let app: NestFastifyApplication | DefidBin +let controller: FeeController | DFeeController let client: JsonRpcClient beforeAll(async () => { - await container.start() - await container.waitForWalletCoinbaseMaturity() - await container.waitForWalletBalanceGTE(100) + if (process.env.DEFID !== undefined) { + app = new DefidBin() + await app.start() + container = app.rpc + controller = app.ocean.feeController + await container.waitForWalletCoinbaseMaturity() + await container.waitForWalletBalanceGTE(100) + } else { + container = new MasterNodeRegTestContainer() + await container.start() + await container.waitForWalletCoinbaseMaturity() + await container.waitForWalletBalanceGTE(100) + app = await createTestingApp(container) + controller = app.get(FeeController) + } - app = await createTestingApp(container) - controller = app.get(FeeController) client = new JsonRpcClient(await container.getCachedRpcUrl()) }) afterAll(async () => { - await stopTestingApp(container, app) + if (process.env.DEFID !== undefined) { + await (app as DefidBin).stop() + return + } + await stopTestingApp(container as MasterNodeRegTestContainer, app as NestFastifyApplication) }) describe('fee/estimate', () => { diff --git a/apps/whale-api/src/module.api/governance.controller.e2e.ts b/apps/whale-api/src/module.api/governance.controller.e2e.ts index 7ba6486a56..25b265c7fe 100644 --- a/apps/whale-api/src/module.api/governance.controller.e2e.ts +++ b/apps/whale-api/src/module.api/governance.controller.e2e.ts @@ -11,6 +11,7 @@ import { NestFastifyApplication } from '@nestjs/platform-fastify' import BigNumber from 'bignumber.js' import { createTestingApp, stopTestingApp } from '../e2e.module' import { GovernanceController } from './governance.controller' +import { DefidBin, DGovernanceController } from '../e2e.defid.module' class MultiOperatorGovernanceMasterNodeRegTestContainer extends MasterNodeRegTestContainer { protected getCmd (opts: StartOptions): string[] { @@ -22,8 +23,8 @@ class MultiOperatorGovernanceMasterNodeRegTestContainer extends MasterNodeRegTes } } const container = new MultiOperatorGovernanceMasterNodeRegTestContainer() -let app: NestFastifyApplication -let controller: GovernanceController +let app: NestFastifyApplication | DefidBin +let controller: GovernanceController | DGovernanceController const testing = Testing.create(container) let cfpProposalId: string let vocProposalId: string @@ -39,7 +40,11 @@ describe('governance - listProposals and getProposal', () => { ]) await testing.container.generate(1) app = await createTestingApp(container) - controller = app.get(GovernanceController) + if (app instanceof DefidBin) { + controller = app.governanceController + } else { + controller = app.get(GovernanceController) + } // Create 1 CFP + 1 VOC payoutAddress = await testing.generateAddress() @@ -259,7 +264,11 @@ describe('governance - listProposalVotes', () => { ]) await testing.container.generate(1) app = await createTestingApp(container) - controller = app.get(GovernanceController) + if (app instanceof DefidBin) { + controller = app.governanceController + } else { + controller = app.get(GovernanceController) + } /** * Import the private keys of the masternode_operator in order to be able to mint blocks and vote on proposals. diff --git a/apps/whale-api/src/module.api/masternode.controller.e2e.ts b/apps/whale-api/src/module.api/masternode.controller.e2e.ts index 42debd6f67..5dfcfb52d3 100644 --- a/apps/whale-api/src/module.api/masternode.controller.e2e.ts +++ b/apps/whale-api/src/module.api/masternode.controller.e2e.ts @@ -6,11 +6,12 @@ import { MasternodeController } from './masternode.controller' import { JsonRpcClient } from '@defichain/jellyfish-api-jsonrpc' import { MasternodeState } from '@defichain/whale-api-client/dist/api/masternodes' import { MasternodeTimeLock } from '@defichain/jellyfish-api-core/dist/category/masternode' +import { DefidBin, DMasternodeController } from '../e2e.defid.module' describe('list', () => { const container = new MasterNodeRegTestContainer() - let app: NestFastifyApplication - let controller: MasternodeController + let app: NestFastifyApplication | DefidBin + let controller: MasternodeController | DMasternodeController let client: JsonRpcClient beforeAll(async () => { @@ -18,7 +19,11 @@ describe('list', () => { app = await createTestingApp(container) client = new JsonRpcClient(await container.getCachedRpcUrl()) - controller = app.get(MasternodeController) + if (app instanceof DefidBin) { + controller = app.masternodeController + } else { + controller = app.get(MasternodeController) + } await container.generate(1) const height = await client.blockchain.getBlockCount() @@ -58,8 +63,8 @@ describe('list', () => { describe('get', () => { const container = new MasterNodeRegTestContainer() - let app: NestFastifyApplication - let controller: MasternodeController + let app: NestFastifyApplication | DefidBin + let controller: MasternodeController | DMasternodeController let client: JsonRpcClient beforeAll(async () => { @@ -67,7 +72,11 @@ describe('get', () => { app = await createTestingApp(container) client = new JsonRpcClient(await container.getCachedRpcUrl()) - controller = app.get(MasternodeController) + if (app instanceof DefidBin) { + controller = app.masternodeController + } else { + controller = app.get(MasternodeController) + } await container.generate(1) const height = await client.blockchain.getBlockCount() @@ -105,8 +114,8 @@ describe('get', () => { describe('resign', () => { const container = new DelayedEunosPayaTestContainer() - let app: NestFastifyApplication - let controller: MasternodeController + let app: NestFastifyApplication | DefidBin + let controller: MasternodeController | DMasternodeController let client: JsonRpcClient beforeAll(async () => { @@ -115,7 +124,11 @@ describe('resign', () => { app = await createTestingApp(container) client = new JsonRpcClient(await container.getCachedRpcUrl()) - controller = app.get(MasternodeController) + if (app instanceof DefidBin) { + controller = app.masternodeController + } else { + controller = app.get(MasternodeController) + } await container.generate(1) const height = await client.blockchain.getBlockCount() @@ -154,8 +167,8 @@ describe('resign', () => { describe('timelock', () => { const container = new MasterNodeRegTestContainer() - let app: NestFastifyApplication - let controller: MasternodeController + let app: NestFastifyApplication | DefidBin + let controller: MasternodeController | DMasternodeController let client: JsonRpcClient beforeAll(async () => { @@ -164,7 +177,11 @@ describe('timelock', () => { app = await createTestingApp(container) client = new JsonRpcClient(await container.getCachedRpcUrl()) - controller = app.get(MasternodeController) + if (app instanceof DefidBin) { + controller = app.masternodeController + } else { + controller = app.get(MasternodeController) + } await container.generate(1) const height = await client.blockchain.getBlockCount() diff --git a/apps/whale-api/src/module.api/poolpair.controller.e2e.ts b/apps/whale-api/src/module.api/poolpair.controller.e2e.ts index 4c8410bc75..fb23566a9f 100644 --- a/apps/whale-api/src/module.api/poolpair.controller.e2e.ts +++ b/apps/whale-api/src/module.api/poolpair.controller.e2e.ts @@ -9,10 +9,11 @@ import { DeFiDCache } from './cache/defid.cache' import { CachePrefix } from '@defichain-apps/libs/caches' import { Cache } from 'cache-manager' import { TokenInfo } from '@defichain/jellyfish-api-core/dist/category/token' +import { DefidBin, DPoolPairController } from '../e2e.defid.module' const container = new MasterNodeRegTestContainer() -let app: NestFastifyApplication -let controller: PoolPairController +let app: NestFastifyApplication | DefidBin +let controller: PoolPairController | DPoolPairController beforeAll(async () => { await container.start() @@ -21,7 +22,11 @@ beforeAll(async () => { await setup() app = await createTestingApp(container) - controller = app.get(PoolPairController) + if (app instanceof DefidBin) { + controller = app.poolPairController + } else { + controller = app.get(PoolPairController) + } const cache = app.get(CACHE_MANAGER) const defiCache = app.get(DeFiDCache) diff --git a/apps/whale-api/src/module.api/poolpair.controller.ts b/apps/whale-api/src/module.api/poolpair.controller.ts index 59d2da6d7f..ac4788388d 100644 --- a/apps/whale-api/src/module.api/poolpair.controller.ts +++ b/apps/whale-api/src/module.api/poolpair.controller.ts @@ -109,7 +109,7 @@ export class PoolPairController { * @param {PaginationQuery} query with size restricted to 20 * @param {number} query.size * @param {string} [query.next] - * @return {Promise>} + * @return {Promise>} */ @Get('/:id/swaps/verbose') async listPoolSwapsVerbose ( @@ -140,7 +140,7 @@ export class PoolPairController { * @param {PaginationQuery} query * @param {number} query.size * @param {string} [query.next] - * @return {Promise>} + * @return {Promise>} */ @Get('/:id/swaps/aggregate/:interval') async listPoolSwapAggregates ( diff --git a/apps/whale-api/src/module.api/rawtx.controller.e2e.ts b/apps/whale-api/src/module.api/rawtx.controller.e2e.ts index d1dd9c8196..38493f5c75 100644 --- a/apps/whale-api/src/module.api/rawtx.controller.e2e.ts +++ b/apps/whale-api/src/module.api/rawtx.controller.e2e.ts @@ -7,10 +7,11 @@ import { NestFastifyApplication } from '@nestjs/platform-fastify' import { createTestingApp, stopTestingApp } from '../e2e.module' import { RawtxController } from './rawtx.controller' import { NotFoundException } from '@nestjs/common' +import { DRawTxController, DefidBin } from '../e2e.defid.module' const container = new MasterNodeRegTestContainer() -let app: NestFastifyApplication -let controller: RawtxController +let app: NestFastifyApplication | DefidBin +let controller: RawtxController | DRawTxController beforeAll(async () => { await container.start() @@ -18,7 +19,11 @@ beforeAll(async () => { await container.waitForWalletBalanceGTE(100) app = await createTestingApp(container) - controller = app.get(RawtxController) + if (app instanceof DefidBin) { + controller = app.rawTxController + } else { + controller = app.get(RawtxController) + } }) afterAll(async () => { diff --git a/apps/whale-api/src/module.api/stats.controller.e2e.ts b/apps/whale-api/src/module.api/stats.controller.e2e.ts index f7aa11bdaa..f9a8bf6bb2 100644 --- a/apps/whale-api/src/module.api/stats.controller.e2e.ts +++ b/apps/whale-api/src/module.api/stats.controller.e2e.ts @@ -2,10 +2,11 @@ import { MasterNodeRegTestContainer } from '@defichain/testcontainers' import { StatsController } from './stats.controller' import { createTestingApp, stopTestingApp, waitForIndexedHeight } from '../e2e.module' import { NestFastifyApplication } from '@nestjs/platform-fastify' +import { DefidBin, DStatsController } from '../e2e.defid.module' const container = new MasterNodeRegTestContainer() -let app: NestFastifyApplication -let controller: StatsController +let app: NestFastifyApplication | DefidBin +let controller: StatsController | DStatsController beforeAll(async () => { await container.start() @@ -14,7 +15,11 @@ beforeAll(async () => { app = await createTestingApp(container) await waitForIndexedHeight(app, 100) - controller = app.get(StatsController) + if (app instanceof DefidBin) { + controller = app.statsController + } else { + controller = app.get(StatsController) + } }) afterAll(async () => { diff --git a/apps/whale-api/src/module.api/token.controller.e2e.ts b/apps/whale-api/src/module.api/token.controller.e2e.ts index 27da35c190..ca4951bb9c 100644 --- a/apps/whale-api/src/module.api/token.controller.e2e.ts +++ b/apps/whale-api/src/module.api/token.controller.e2e.ts @@ -4,28 +4,44 @@ import { NestFastifyApplication } from '@nestjs/platform-fastify' import { createTestingApp, stopTestingApp, waitForIndexedHeight } from '../e2e.module' import { createPoolPair, createToken } from '@defichain/testing' import { NotFoundException } from '@nestjs/common' +import { DTokenController, DefidBin, DefidRpc } from '../e2e.defid.module' -const container = new MasterNodeRegTestContainer() -let app: NestFastifyApplication -let controller: TokenController +let container: MasterNodeRegTestContainer | DefidRpc +let app: NestFastifyApplication | DefidBin +let controller: TokenController | DTokenController beforeAll(async () => { - await container.start() - await container.waitForWalletCoinbaseMaturity() - await container.waitForWalletBalanceGTE(100) - - app = await createTestingApp(container) - controller = app.get(TokenController) - - await waitForIndexedHeight(app, 100) - - await createToken(container, 'DBTC') - await createToken(container, 'DETH') - await createPoolPair(container, 'DBTC', 'DETH') + if (process.env.DEFID !== undefined) { + app = new DefidBin() + await app.start() + container = app.rpc + controller = app.ocean.tokenController + await container.waitForWalletCoinbaseMaturity() + await container.waitForWalletBalanceGTE(100) + await waitForIndexedHeight(app, 100) + await container.createToken('DBTC') + await container.createToken('DETH') + await container.createPoolPair('DBTC', 'DETH') + } else { + container = new MasterNodeRegTestContainer() + await container.start() + app = await createTestingApp(container) + controller = app.get(TokenController) + await container.waitForWalletCoinbaseMaturity() + await container.waitForWalletBalanceGTE(100) + await waitForIndexedHeight(app, 100) + await createToken(container, 'DBTC') + await createToken(container, 'DETH') + await createPoolPair(container, 'DBTC', 'DETH') + } }) afterAll(async () => { - await stopTestingApp(container, app) + if (process.env.DEFID !== undefined) { + await (app as DefidBin).stop() + return + } + await stopTestingApp(container as MasterNodeRegTestContainer, app as NestFastifyApplication) }) describe('list', () => { diff --git a/apps/whale-api/src/module.api/transaction.controller.e2e.ts b/apps/whale-api/src/module.api/transaction.controller.e2e.ts index e0526d6db7..f14e369c92 100644 --- a/apps/whale-api/src/module.api/transaction.controller.e2e.ts +++ b/apps/whale-api/src/module.api/transaction.controller.e2e.ts @@ -4,10 +4,11 @@ import { TransactionController } from './transaction.controller' import { NestFastifyApplication } from '@nestjs/platform-fastify' import { createTestingApp, stopTestingApp, waitForIndexedHeight } from '../e2e.module' import { NotFoundException } from '@nestjs/common' +import { DTransactionController, DefidBin } from '../e2e.defid.module' const container = new MasterNodeRegTestContainer() -let app: NestFastifyApplication -let controller: TransactionController +let app: NestFastifyApplication | DefidBin +let controller: TransactionController | DTransactionController let client: JsonRpcClient beforeAll(async () => { @@ -16,7 +17,11 @@ beforeAll(async () => { await container.waitForWalletBalanceGTE(100) app = await createTestingApp(container) - controller = app.get(TransactionController) + if (app instanceof DefidBin) { + controller = app.transactionController + } else { + controller = app.get(TransactionController) + } client = new JsonRpcClient(await container.getCachedRpcUrl()) await waitForIndexedHeight(app, 100)