diff --git a/src/endpoints/transactions/token.transfer.service.ts b/src/endpoints/transactions/token.transfer.service.ts new file mode 100644 index 000000000..55ac908ba --- /dev/null +++ b/src/endpoints/transactions/token.transfer.service.ts @@ -0,0 +1,110 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { BinaryUtils } from "src/utils/binary.utils"; +import { TransactionLog } from "./entities/transaction.log"; +import { TransactionLogEvent } from "./entities/transaction.log.event"; +import { TransactionLogEventIdentifier } from "./entities/transaction.log.event.identifier"; +import { TransactionOperation } from "./entities/transaction.operation"; +import { TransactionOperationAction } from "./entities/transaction.operation.action"; +import { TransactionOperationType } from "./entities/transaction.operation.type"; + +@Injectable() +export class TokenTransferService { + private readonly logger: Logger + + constructor( + ) { + this.logger = new Logger(TokenTransferService.name); + } + + getTokenTransfer(elasticTransaction: any): { tokenIdentifier: string, tokenAmount: string } | undefined { + if (!elasticTransaction.data) { + return undefined; + } + + let tokens = elasticTransaction.tokens; + if (!tokens || tokens.length === 0) { + return undefined; + } + + let esdtValues = elasticTransaction.esdtValues; + if (!esdtValues || esdtValues.length === 0) { + return undefined; + } + + let decodedData = BinaryUtils.base64Decode(elasticTransaction.data); + if (!decodedData.startsWith('ESDTTransfer@')) { + return undefined; + } + + let token = tokens[0]; + let esdtValue = esdtValues[0]; + + return { tokenIdentifier: token, tokenAmount: esdtValue }; + } + + getOperationsForTransactionLogs(txHash: string, logs: TransactionLog[]): TransactionOperation[] { + let operations: (TransactionOperation | undefined)[] = []; + + for (let log of logs) { + for (let event of log.events) { + switch (event.identifier) { + case TransactionLogEventIdentifier.ESDTNFTTransfer: + operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.transfer)); + break; + case TransactionLogEventIdentifier.ESDTNFTBurn: + operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.burn)); + break; + case TransactionLogEventIdentifier.ESDTNFTAddQuantity: + operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.addQuantity)); + break; + case TransactionLogEventIdentifier.ESDTNFTCreate: + operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.create)); + break; + case TransactionLogEventIdentifier.MultiESDTNFTTransfer: + operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.multiTransfer)); + break; + case TransactionLogEventIdentifier.ESDTTransfer: + operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.transfer)); + break; + case TransactionLogEventIdentifier.ESDTBurn: + operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.burn)); + break; + case TransactionLogEventIdentifier.ESDTLocalMint: + operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.localMint)); + break; + case TransactionLogEventIdentifier.ESDTLocalBurn: + operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.localBurn)); + break; + case TransactionLogEventIdentifier.ESDTWipe: + operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.wipe)); + break; + } + } + } + + return operations.filter(operation => operation !== undefined).map(operation => operation!); + } + + private getTransactionNftOperation(txHash: string, log: TransactionLog, event: TransactionLogEvent, action: TransactionOperationAction): TransactionOperation | undefined { + try { + let identifier = BinaryUtils.base64Decode(event.topics[0]); + let nonce = BinaryUtils.tryBase64ToHex(event.topics[1]); + let value = BinaryUtils.tryBase64ToBigInt(event.topics[2])?.toString() ?? '0'; + let receiver = BinaryUtils.tryBase64ToAddress(event.topics[3]) ?? log.address; + + let collection: string | undefined = undefined; + if (nonce) { + collection = identifier; + identifier = `${collection}-${nonce}` + } + + let type = nonce ? TransactionOperationType.nft : TransactionOperationType.esdt; + + return { action, type, collection, identifier, sender: event.address, receiver, value }; + } catch (error) { + this.logger.error(`Error when parsing NFT transaction log for tx hash '${txHash}' with action '${action}' and topics: ${event.topics}`); + this.logger.error(error); + return undefined; + } + } +} \ No newline at end of file diff --git a/src/endpoints/transactions/transaction.get.service.ts b/src/endpoints/transactions/transaction.get.service.ts new file mode 100644 index 000000000..c93d24c82 --- /dev/null +++ b/src/endpoints/transactions/transaction.get.service.ts @@ -0,0 +1,197 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { ApiConfigService } from "src/common/api.config.service"; +import { ElasticService } from "src/common/elastic.service"; +import { ElasticQuery } from "src/common/entities/elastic/elastic.query"; +import { ElasticSortOrder } from "src/common/entities/elastic/elastic.sort.order"; +import { ElasticSortProperty } from "src/common/entities/elastic/elastic.sort.property"; +import { QueryType } from "src/common/entities/elastic/query.type"; +import { GatewayService } from "src/common/gateway.service"; +import { ApiUtils } from "src/utils/api.utils"; +import { BinaryUtils } from "src/utils/binary.utils"; +import { SmartContractResult } from "./entities/smart.contract.result"; +import { Transaction } from "./entities/transaction"; +import { TransactionDetailed } from "./entities/transaction.detailed"; +import { TransactionLog } from "./entities/transaction.log"; +import { TransactionReceipt } from "./entities/transaction.receipt"; +import { TokenTransferService } from "./token.transfer.service"; + +@Injectable() +export class TransactionGetService { + private readonly logger: Logger + + constructor( + private readonly elasticService: ElasticService, + private readonly gatewayService: GatewayService, + private readonly apiConfigService: ApiConfigService, + private readonly tokenTransferService: TokenTransferService, + ) { + this.logger = new Logger(TransactionGetService.name); + } + + private async tryGetTransactionFromElasticBySenderAndNonce(sender: string, nonce: number): Promise { + const query: ElasticQuery = new ElasticQuery(); + query.pagination = { from: 0, size: 1 }; + + query.condition.must = [ + QueryType.Match('sender', sender), + QueryType.Match('nonce', nonce) + ]; + + let transactions = await this.elasticService.getList('transactions', 'txHash', query); + + return transactions.firstOrUndefined(); + } + + async tryGetTransactionFromElastic(txHash: string): Promise { + try { + const result = await this.elasticService.getItem('transactions', 'txHash', txHash); + if (!result) { + return null; + } + + if (result.scResults) { + result.results = result.scResults; + } + + let transactionDetailed: TransactionDetailed = ApiUtils.mergeObjects(new TransactionDetailed(), result); + let tokenTransfer = this.tokenTransferService.getTokenTransfer(result); + if (tokenTransfer) { + transactionDetailed.tokenValue = tokenTransfer.tokenAmount; + transactionDetailed.tokenIdentifier = tokenTransfer.tokenIdentifier; + } + + const hashes: string[] = []; + hashes.push(txHash); + + if (!this.apiConfigService.getUseLegacyElastic()) { + const elasticQueryAdapterSc: ElasticQuery = new ElasticQuery(); + elasticQueryAdapterSc.pagination = { from: 0, size: 100 }; + + const timestamp: ElasticSortProperty = { name: 'timestamp', order: ElasticSortOrder.ascending }; + elasticQueryAdapterSc.sort = [timestamp]; + + const originalTxHashQuery = QueryType.Match('originalTxHash', txHash); + elasticQueryAdapterSc.condition.must = [originalTxHashQuery]; + + if (result.hasScResults === true) { + let scResults = await this.elasticService.getList('scresults', 'scHash', elasticQueryAdapterSc); + for (let scResult of scResults) { + scResult.hash = scResult.scHash; + hashes.push(scResult.hash); + + delete scResult.scHash; + } + + transactionDetailed.results = scResults.map(scResult => ApiUtils.mergeObjects(new SmartContractResult(), scResult)); + } + + const elasticQueryAdapterReceipts: ElasticQuery = new ElasticQuery(); + elasticQueryAdapterReceipts.pagination = { from: 0, size: 1 }; + + const receiptHashQuery = QueryType.Match('receiptHash', txHash); + elasticQueryAdapterReceipts.condition.must = [receiptHashQuery]; + + let receipts = await this.elasticService.getList('receipts', 'receiptHash', elasticQueryAdapterReceipts); + if (receipts.length > 0) { + let receipt = receipts[0]; + transactionDetailed.receipt = ApiUtils.mergeObjects(new TransactionReceipt(), receipt); + } + + const elasticQueryAdapterLogs: ElasticQuery = new ElasticQuery(); + elasticQueryAdapterLogs.pagination = { from: 0, size: 100 }; + + let queries = []; + for (let hash of hashes) { + queries.push(QueryType.Match('_id', hash)); + } + elasticQueryAdapterLogs.condition.should = queries; + + let logs: any[] = await this.elasticService.getLogsForTransactionHashes(elasticQueryAdapterLogs); + let transactionLogs = logs.map(log => ApiUtils.mergeObjects(new TransactionLog(), log._source)); + + transactionDetailed.operations = this.tokenTransferService.getOperationsForTransactionLogs(txHash, transactionLogs); + + for (let log of logs) { + if (log._id === txHash) { + transactionDetailed.logs = ApiUtils.mergeObjects(new TransactionLog(), log._source); + } + else { + const foundScResult = transactionDetailed.results.find(({ hash }) => log._id === hash); + if (foundScResult) { + foundScResult.logs = ApiUtils.mergeObjects(new TransactionLog(), log._source); + } + } + } + } + + return ApiUtils.mergeObjects(new TransactionDetailed(), transactionDetailed); + } catch (error) { + this.logger.error(error); + return null; + } + } + + async tryGetTransactionFromGatewayForList(txHash: string) { + const gatewayTransaction = await this.tryGetTransactionFromGateway(txHash, false); + if (gatewayTransaction) { + return ApiUtils.mergeObjects(new Transaction(), gatewayTransaction); + } + return undefined; //invalid hash + } + + async tryGetTransactionFromGateway(txHash: string, queryInElastic: boolean = true): Promise { + try { + const { transaction } = await this.gatewayService.get(`transaction/${txHash}?withResults=true`); + + if (transaction.status === 'pending' && queryInElastic) { + let existingTransaction = await this.tryGetTransactionFromElasticBySenderAndNonce(transaction.sender, transaction.nonce); + if (existingTransaction && existingTransaction.txHash !== txHash) { + return null; + } + } + + if (transaction.receipt) { + transaction.receipt.value = transaction.receipt.value.toString(); + } + + if (transaction.smartContractResults) { + for (let smartContractResult of transaction.smartContractResults) { + smartContractResult.callType = smartContractResult.callType.toString(); + smartContractResult.value = smartContractResult.value.toString(); + + if (smartContractResult.data) { + smartContractResult.data = BinaryUtils.base64Encode(smartContractResult.data); + } + } + } + + let result = { + txHash: txHash, + data: transaction.data, + gasLimit: transaction.gasLimit, + gasPrice: transaction.gasPrice, + gasUsed: transaction.gasUsed, + miniBlockHash: transaction.miniblockHash, + senderShard: transaction.sourceShard, + receiverShard: transaction.destinationShard, + nonce: transaction.nonce, + receiver: transaction.receiver, + sender: transaction.sender, + signature: transaction.signature, + status: transaction.status, + value: transaction.value, + round: transaction.round, + fee: transaction.fee, + timestamp: transaction.timestamp, + scResults: transaction.smartContractResults ? transaction.smartContractResults.map((scResult: any) => ApiUtils.mergeObjects(new SmartContractResult(), scResult)) : [], + receipt: transaction.receipt ? ApiUtils.mergeObjects(new TransactionReceipt(), transaction.receipt) : undefined, + logs: transaction.logs + }; + + return ApiUtils.mergeObjects(new TransactionDetailed(), result); + } catch (error) { + this.logger.error(error); + return null; + } + } +} \ No newline at end of file diff --git a/src/endpoints/transactions/transaction.service.ts b/src/endpoints/transactions/transaction.service.ts index aba0620b9..d3fce8486 100644 --- a/src/endpoints/transactions/transaction.service.ts +++ b/src/endpoints/transactions/transaction.service.ts @@ -10,24 +10,17 @@ import { QueryType } from 'src/common/entities/elastic/query.type'; import { GatewayService } from 'src/common/gateway.service'; import { AddressUtils } from 'src/utils/address.utils'; import { ApiUtils } from 'src/utils/api.utils'; -import { BinaryUtils } from 'src/utils/binary.utils'; import { ElasticService } from '../../common/elastic.service'; -import { SmartContractResult } from './entities/smart.contract.result'; import { Transaction } from './entities/transaction'; import { TransactionCreate } from './entities/transaction.create'; import { TransactionDetailed } from './entities/transaction.detailed'; import { TransactionFilter } from './entities/transaction.filter'; -import { TransactionLog } from './entities/transaction.log'; -import { TransactionLogEvent } from './entities/transaction.log.event'; -import { TransactionLogEventIdentifier } from './entities/transaction.log.event.identifier'; -import { TransactionOperation } from './entities/transaction.operation'; -import { TransactionReceipt } from './entities/transaction.receipt'; import { TransactionSendResult } from './entities/transaction.send.result'; -import { TransactionOperationType } from './entities/transaction.operation.type'; -import { TransactionOperationAction } from './entities/transaction.operation.action'; import { QueryOperator } from 'src/common/entities/elastic/query.operator'; import { TransactionScamCheckService } from './scam-check/transaction-scam-check.service'; import { TransactionScamInfo } from './entities/transaction-scam-info'; +import { TransactionGetService } from './transaction.get.service'; +import { TokenTransferService } from './token.transfer.service'; import { TransactionPriceService } from './transaction.price.service'; @Injectable() @@ -40,6 +33,8 @@ export class TransactionService { private readonly apiConfigService: ApiConfigService, private readonly transactionPriceService: TransactionPriceService, private readonly transactionScamCheckService: TransactionScamCheckService, + private readonly transactionGetService: TransactionGetService, + private readonly tokenTransferService: TokenTransferService, ) { this.logger = new Logger(TransactionService.name); } @@ -129,7 +124,7 @@ export class TransactionService { const elasticHashes = elasticTransactions.map(({txHash}) => txHash); const missingHashes: string[] = txHashes.findMissingElements(elasticHashes); - let gatewayTransactions = await Promise.all(missingHashes.map((txHash) => this.tryGetTransactionFromGatewayForList(txHash))); + let gatewayTransactions = await Promise.all(missingHashes.map((txHash) => this.transactionGetService.tryGetTransactionFromGatewayForList(txHash))); for (let gatewayTransaction of gatewayTransactions) { if (gatewayTransaction) { transactions.push(gatewayTransaction); @@ -140,7 +135,7 @@ export class TransactionService { for (let elasticTransaction of elasticTransactions) { let transaction = ApiUtils.mergeObjects(new Transaction(), elasticTransaction); - let tokenTransfer = this.getTokenTransfer(elasticTransaction); + let tokenTransfer = this.tokenTransferService.getTokenTransfer(elasticTransaction); if (tokenTransfer) { transaction.tokenValue = tokenTransfer.tokenAmount; transaction.tokenIdentifier = tokenTransfer.tokenIdentifier; @@ -152,37 +147,11 @@ export class TransactionService { return transactions; } - private getTokenTransfer(elasticTransaction: any): { tokenIdentifier: string, tokenAmount: string } | undefined { - if (!elasticTransaction.data) { - return undefined; - } - - let tokens = elasticTransaction.tokens; - if (!tokens || tokens.length === 0) { - return undefined; - } - - let esdtValues = elasticTransaction.esdtValues; - if (!esdtValues || esdtValues.length === 0) { - return undefined; - } - - let decodedData = BinaryUtils.base64Decode(elasticTransaction.data); - if (!decodedData.startsWith('ESDTTransfer@')) { - return undefined; - } - - let token = tokens[0]; - let esdtValue = esdtValues[0]; - - return { tokenIdentifier: token, tokenAmount: esdtValue }; - } - async getTransaction(txHash: string): Promise { - let transaction = await this.tryGetTransactionFromElastic(txHash); + let transaction = await this.transactionGetService.tryGetTransactionFromElastic(txHash); if (transaction === null) { - transaction = await this.tryGetTransactionFromGateway(txHash); + transaction = await this.transactionGetService.tryGetTransactionFromGateway(txHash); } if (transaction !== null) { @@ -203,239 +172,6 @@ export class TransactionService { return transaction; } - private async tryGetTransactionFromElasticBySenderAndNonce(sender: string, nonce: number): Promise { - const query: ElasticQuery = new ElasticQuery(); - query.pagination = { from: 0, size: 1 }; - - query.condition.must = [ - QueryType.Match('sender', sender), - QueryType.Match('nonce', nonce) - ]; - - let transactions = await this.elasticService.getList('transactions', 'txHash', query); - - return transactions.firstOrUndefined(); - } - - async tryGetTransactionFromElastic(txHash: string): Promise { - try { - const result = await this.elasticService.getItem('transactions', 'txHash', txHash); - if (!result) { - return null; - } - - if (result.scResults) { - result.results = result.scResults; - } - - let transactionDetailed: TransactionDetailed = ApiUtils.mergeObjects(new TransactionDetailed(), result); - let tokenTransfer = this.getTokenTransfer(result); - if (tokenTransfer) { - transactionDetailed.tokenValue = tokenTransfer.tokenAmount; - transactionDetailed.tokenIdentifier = tokenTransfer.tokenIdentifier; - } - - const hashes: string[] = []; - hashes.push(txHash); - - if (!this.apiConfigService.getUseLegacyElastic()) { - const elasticQueryAdapterSc: ElasticQuery = new ElasticQuery(); - elasticQueryAdapterSc.pagination = { from: 0, size: 100 }; - - const timestamp: ElasticSortProperty = { name: 'timestamp', order: ElasticSortOrder.ascending }; - elasticQueryAdapterSc.sort = [timestamp]; - - const originalTxHashQuery = QueryType.Match('originalTxHash', txHash); - elasticQueryAdapterSc.condition.must = [originalTxHashQuery]; - - if (result.hasScResults === true) { - let scResults = await this.elasticService.getList('scresults', 'scHash', elasticQueryAdapterSc); - for (let scResult of scResults) { - scResult.hash = scResult.scHash; - hashes.push(scResult.hash); - - delete scResult.scHash; - } - - transactionDetailed.results = scResults.map(scResult => ApiUtils.mergeObjects(new SmartContractResult(), scResult)); - } - - const elasticQueryAdapterReceipts: ElasticQuery = new ElasticQuery(); - elasticQueryAdapterReceipts.pagination = { from: 0, size: 1 }; - - const receiptHashQuery = QueryType.Match('receiptHash', txHash); - elasticQueryAdapterReceipts.condition.must = [receiptHashQuery]; - - let receipts = await this.elasticService.getList('receipts', 'receiptHash', elasticQueryAdapterReceipts); - if (receipts.length > 0) { - let receipt = receipts[0]; - transactionDetailed.receipt = ApiUtils.mergeObjects(new TransactionReceipt(), receipt); - } - - const elasticQueryAdapterLogs: ElasticQuery = new ElasticQuery(); - elasticQueryAdapterLogs.pagination = { from: 0, size: 100 }; - - let queries = []; - for (let hash of hashes) { - queries.push(QueryType.Match('_id', hash)); - } - elasticQueryAdapterLogs.condition.should = queries; - - let logs: any[] = await this.elasticService.getLogsForTransactionHashes(elasticQueryAdapterLogs); - let transactionLogs = logs.map(log => ApiUtils.mergeObjects(new TransactionLog(), log._source)); - - transactionDetailed.operations = this.getOperationsForTransactionLogs(txHash, transactionLogs); - - for (let log of logs) { - if (log._id === txHash) { - transactionDetailed.logs = ApiUtils.mergeObjects(new TransactionLog(), log._source); - } - else { - const foundScResult = transactionDetailed.results.find(({ hash }) => log._id === hash); - if (foundScResult) { - foundScResult.logs = ApiUtils.mergeObjects(new TransactionLog(), log._source); - } - } - } - } - - return ApiUtils.mergeObjects(new TransactionDetailed(), transactionDetailed); - } catch (error) { - this.logger.error(error); - return null; - } - } - - getOperationsForTransactionLogs(txHash: string, logs: TransactionLog[]): TransactionOperation[] { - let operations: (TransactionOperation | undefined)[] = []; - - for (let log of logs) { - for (let event of log.events) { - switch (event.identifier) { - case TransactionLogEventIdentifier.ESDTNFTTransfer: - operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.transfer)); - break; - case TransactionLogEventIdentifier.ESDTNFTBurn: - operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.burn)); - break; - case TransactionLogEventIdentifier.ESDTNFTAddQuantity: - operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.addQuantity)); - break; - case TransactionLogEventIdentifier.ESDTNFTCreate: - operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.create)); - break; - case TransactionLogEventIdentifier.MultiESDTNFTTransfer: - operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.multiTransfer)); - break; - case TransactionLogEventIdentifier.ESDTTransfer: - operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.transfer)); - break; - case TransactionLogEventIdentifier.ESDTBurn: - operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.burn)); - break; - case TransactionLogEventIdentifier.ESDTLocalMint: - operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.localMint)); - break; - case TransactionLogEventIdentifier.ESDTLocalBurn: - operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.localBurn)); - break; - case TransactionLogEventIdentifier.ESDTWipe: - operations.push(this.getTransactionNftOperation(txHash, log, event, TransactionOperationAction.wipe)); - break; - } - } - } - - return operations.filter(operation => operation !== undefined).map(operation => operation!); - } - - private getTransactionNftOperation(txHash: string, log: TransactionLog, event: TransactionLogEvent, action: TransactionOperationAction): TransactionOperation | undefined { - try { - let identifier = BinaryUtils.base64Decode(event.topics[0]); - let nonce = BinaryUtils.tryBase64ToHex(event.topics[1]); - let value = BinaryUtils.tryBase64ToBigInt(event.topics[2])?.toString() ?? '0'; - let receiver = BinaryUtils.tryBase64ToAddress(event.topics[3]) ?? log.address; - - let collection: string | undefined = undefined; - if (nonce) { - collection = identifier; - identifier = `${collection}-${nonce}` - } - - let type = nonce ? TransactionOperationType.nft : TransactionOperationType.esdt; - - return { action, type, collection, identifier, sender: event.address, receiver, value }; - } catch (error) { - this.logger.error(`Error when parsing NFT transaction log for tx hash '${txHash}' with action '${action}' and topics: ${event.topics}`); - this.logger.error(error); - return undefined; - } - } - - async tryGetTransactionFromGatewayForList(txHash: string) { - const gatewayTransaction = await this.tryGetTransactionFromGateway(txHash, false); - if (gatewayTransaction) { - return ApiUtils.mergeObjects(new Transaction(), gatewayTransaction); - } - return undefined; //invalid hash - } - - async tryGetTransactionFromGateway(txHash: string, queryInElastic: boolean = true): Promise { - try { - const { transaction } = await this.gatewayService.get(`transaction/${txHash}?withResults=true`); - - if (transaction.status === 'pending' && queryInElastic) { - let existingTransaction = await this.tryGetTransactionFromElasticBySenderAndNonce(transaction.sender, transaction.nonce); - if (existingTransaction && existingTransaction.txHash !== txHash) { - return null; - } - } - - if (transaction.receipt) { - transaction.receipt.value = transaction.receipt.value.toString(); - } - - if (transaction.smartContractResults) { - for (let smartContractResult of transaction.smartContractResults) { - smartContractResult.callType = smartContractResult.callType.toString(); - smartContractResult.value = smartContractResult.value.toString(); - - if (smartContractResult.data) { - smartContractResult.data = BinaryUtils.base64Encode(smartContractResult.data); - } - } - } - - let result = { - txHash: txHash, - data: transaction.data, - gasLimit: transaction.gasLimit, - gasPrice: transaction.gasPrice, - gasUsed: transaction.gasUsed, - miniBlockHash: transaction.miniblockHash, - senderShard: transaction.sourceShard, - receiverShard: transaction.destinationShard, - nonce: transaction.nonce, - receiver: transaction.receiver, - sender: transaction.sender, - signature: transaction.signature, - status: transaction.status, - value: transaction.value, - round: transaction.round, - fee: transaction.fee, - timestamp: transaction.timestamp, - scResults: transaction.smartContractResults ? transaction.smartContractResults.map((scResult: any) => ApiUtils.mergeObjects(new SmartContractResult(), scResult)) : [], - receipt: transaction.receipt ? ApiUtils.mergeObjects(new TransactionReceipt(), transaction.receipt) : undefined, - logs: transaction.logs - }; - - return ApiUtils.mergeObjects(new TransactionDetailed(), result); - } catch (error) { - this.logger.error(error); - return null; - } - } - async createTransaction(transaction: TransactionCreate): Promise { const receiverShard = AddressUtils.computeShard(AddressUtils.bech32Decode(transaction.receiver)); const senderShard = AddressUtils.computeShard(AddressUtils.bech32Decode(transaction.sender)); diff --git a/src/public.app.module.ts b/src/public.app.module.ts index 136501aa1..f267e33cc 100644 --- a/src/public.app.module.ts +++ b/src/public.app.module.ts @@ -63,6 +63,8 @@ import "./utils/extensions/date.extensions"; import "./utils/extensions/number.extensions"; import { NftThumbnailService } from './common/nft.thumbnail.service'; import { NftExtendedAttributesService } from './common/nft.extendedattributes.service'; +import { TransactionGetService } from './endpoints/transactions/transaction.get.service'; +import { TokenTransferService } from './endpoints/transactions/token.transfer.service'; import { TransactionPriceService } from './endpoints/transactions/transaction.price.service'; @Module({ @@ -104,6 +106,7 @@ import { TransactionPriceService } from './endpoints/transactions/transaction.pr DelegationService, CacheConfigService, CachingInterceptor, ShardService, MetricsService, IdentitiesService, TokenAssetService, DataApiService, KeysService, WaitingListService, BlsService, TagService, ExtrasApiService, TransactionScamCheckService, PotentialScamTransactionChecker, NftThumbnailService, NftExtendedAttributesService, + TransactionGetService, TokenTransferService, TransactionPriceService, ], exports: [