hive-keychain-commons
Version:
Platform-agnostic functions used in Hive Keychain mobile and extensions
272 lines (271 loc) • 16 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExportTransactionsUtils = void 0;
const moment_1 = __importDefault(require("moment"));
const index_1 = require("../index");
const transaction_utils_1 = require("./transaction.utils");
const PROPOSAL_FEE = 87;
const COLLATERALIZED_CONVERT_IMMEDIATE_CONVERSION = 88;
const generateCSV = (operations) => {
var _a, _b;
try {
if (!Array.isArray(operations)) {
throw new Error('Input must be an array of operations');
}
if (operations.length === 0) {
return 'Operation Type,Date,Transaction ID, Block number,From,To,Amount,Currency\r\n';
}
let csvContent = `Operation Type,Date,Transaction ID, Block number,From,To,Amount,Currency\r\n`;
for (const operation of operations) {
if (!operation.operationType ||
!operation.datetime ||
!operation.transactionId ||
!operation.blockNumber) {
throw new Error('Missing required fields in operation');
}
const sanitizedValues = {
operationType: String(operation.operationType).replace(/[,\r\n"]/g, ' '),
datetime: String(operation.datetime).replace(/[,\r\n"]/g, ' '),
transactionId: String(operation.transactionId).replace(/[,\r\n"]/g, ' '),
blockNumber: String(operation.blockNumber),
from: ((_a = operation.from) !== null && _a !== void 0 ? _a : 'NA').replace(/[,\r\n"]/g, ' '),
to: ((_b = operation.to) !== null && _b !== void 0 ? _b : 'NA').replace(/[,\r\n"]/g, ' '),
amount: String(operation.amount),
currency: String(operation.currency).replace(/[,\r\n"]/g, ' '),
};
csvContent += `${sanitizedValues.operationType},${sanitizedValues.datetime},${sanitizedValues.transactionId},${sanitizedValues.blockNumber},${sanitizedValues.from},${sanitizedValues.to},${sanitizedValues.amount},${sanitizedValues.currency}\r\n`;
}
return csvContent;
}
catch (error) {
throw new Error(`Failed to generate CSV: ${error.message}`);
}
};
const fetchTransactions = (username, startDate, endDate, feedBack) => __awaiter(void 0, void 0, void 0, function* () {
const MAX_LIMIT = 1000;
const op = index_1.HistoryFiltersUtils.operationOrders;
const operationsBitmask = index_1.HistoryFiltersUtils.makeBitMaskFilter([
op.transfer,
op.interest,
op.transfer_to_vesting,
op.fill_vesting_withdraw,
op.fill_convert_request,
op.fill_collateralized_convert_request,
COLLATERALIZED_CONVERT_IMMEDIATE_CONVERSION,
op.fill_recurrent_transfer,
op.fill_order,
op.producer_reward,
op.claim_reward_balance,
op.escrow_release,
op.account_create,
op.account_create_with_delegation,
op.proposal_pay,
op.escrow_approve,
PROPOSAL_FEE,
]);
const lastTransaction = yield transaction_utils_1.TransactionUtils.getLastTransaction(username);
const limit = Math.min(1000, lastTransaction);
let start = lastTransaction;
let rawTransactions = [];
const operations = [];
let forceStop = false;
let percentageDuration;
if (startDate) {
startDate = (0, moment_1.default)(startDate).startOf('day').toDate();
}
if (!endDate) {
endDate = new Date();
}
else {
endDate = (0, moment_1.default)(endDate).endOf('day').toDate();
}
if (startDate) {
percentageDuration = endDate.getTime() - startDate.getTime();
}
try {
do {
rawTransactions = yield transaction_utils_1.TransactionUtils.getTransactions(username, start, limit, operationsBitmask[0], operationsBitmask[1]);
for (let i = rawTransactions.length - 1; i >= 0; i--) {
const tx = rawTransactions[i];
const operationPayload = tx[1].op[1];
const operationType = tx[1].op[0];
const transactionInfo = tx[1];
// Simple timestamp handling - use original string if parsing fails
let date;
try {
if (process.env.IS_FIREFOX) {
date = (0, moment_1.default)(transactionInfo.timestamp);
}
else {
// Try parsing with timezone marker
const timestamp = transactionInfo.timestamp.endsWith('z') ||
transactionInfo.timestamp.endsWith('Z')
? transactionInfo.timestamp
: transactionInfo.timestamp + 'Z';
date = (0, moment_1.default)(timestamp);
}
}
catch (error) {
console.error('Error parsing timestamp:', error);
date = null; // Fall back to using the original string
}
// Use the original timestamp string if moment parsing failed
const localDatetime = date && date.isValid()
? date.format('YYYY-MM-DD HH:mm:ss')
: transactionInfo.timestamp;
// Ensure date is valid for date comparisons
const validDate = date && date.isValid() ? date : (0, moment_1.default)(new Date());
if (endDate &&
validDate.isSameOrAfter((0, moment_1.default)(endDate).add(1, 'day'), 'day'))
continue;
if (startDate && validDate.isBefore((0, moment_1.default)(startDate), 'day')) {
forceStop = true;
break;
}
const operation = {
operationType,
datetime: localDatetime,
transactionId: transactionInfo.trx_id,
blockNumber: transactionInfo.block,
to: 'NA',
amount: 0,
currency: 'NA',
from: 'NA',
};
switch (operationType) {
case 'transfer':
case 'fill_recurrent_transfer': {
const transferOperation = operationPayload;
const asset = index_1.Asset.fromString(transferOperation.amount.toString());
operations.push(Object.assign(Object.assign({}, operation), { from: transferOperation.from, to: transferOperation.to, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'interest': {
const asset = index_1.Asset.fromString(operationPayload.interest.toString());
operations.push(Object.assign(Object.assign({}, operation), { from: 'NA', to: operationPayload.owner, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'transfer_to_vesting': {
const asset = index_1.Asset.fromString(operationPayload.amount.toString());
operations.push(Object.assign(Object.assign({}, operation), { from: operationPayload.from, to: operationPayload.to, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'fill_vesting_withdraw': {
const asset = index_1.Asset.fromString(operationPayload.deposited.toString());
operations.push(Object.assign(Object.assign({}, operation), { from: operationPayload.from_account, to: operationPayload.to_account, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'fill_convert_request': {
let asset = index_1.Asset.fromString(operationPayload.amount_out.toString());
operations.push(Object.assign(Object.assign({}, operation), { from: operationPayload.owner, to: operationPayload.owner, amount: asset.amount, currency: asset.symbol }));
asset = index_1.Asset.fromString(operationPayload.amount_in.toString());
operations.push(Object.assign(Object.assign({}, operation), { from: operationPayload.owner, to: operationPayload.owner, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'fill_collateralized_convert_request': {
let asset = index_1.Asset.fromString(operationPayload.amount_out.toString());
operations.push(Object.assign(Object.assign({}, operation), { from: operationPayload.owner, to: operationPayload.owner, amount: asset.amount, currency: asset.symbol }));
asset = index_1.Asset.fromString(operationPayload.amount_in.toString());
operations.push(Object.assign(Object.assign({}, operation), { from: operationPayload.owner, to: operationPayload.owner, amount: asset.amount, currency: asset.symbol }));
asset = index_1.Asset.fromString(operationPayload.excess_collateral.toString());
operations.push(Object.assign(Object.assign({}, operation), { from: operationPayload.owner, to: operationPayload.owner, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'producer_reward': {
const asset = index_1.Asset.fromString(operationPayload.vesting_shares.toString());
operations.push(Object.assign(Object.assign({}, operation), { to: operationPayload.producer, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'claim_reward_balance': {
let asset = index_1.Asset.fromString(operationPayload.reward_hive.toString());
if (asset.amount > 0)
operations.push(Object.assign(Object.assign({}, operation), { to: operationPayload.account, amount: asset.amount, currency: asset.symbol }));
asset = index_1.Asset.fromString(operationPayload.reward_hbd.toString());
if (asset.amount > 0)
operations.push(Object.assign(Object.assign({}, operation), { to: operationPayload.account, amount: asset.amount, currency: asset.symbol }));
asset = index_1.Asset.fromString(operationPayload.reward_vests.toString());
if (asset.amount > 0)
operations.push(Object.assign(Object.assign({}, operation), { to: operationPayload.account, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'escrow_release': {
let asset = index_1.Asset.fromString(operationPayload.hbd_amount.toString());
if (asset.amount > 0)
operations.push(Object.assign(Object.assign({}, operation), { to: operationPayload.to, from: operationPayload.from, amount: asset.amount, currency: asset.symbol }));
asset = index_1.Asset.fromString(operationPayload.hive_amount.toString());
if (asset.amount > 0)
operations.push(Object.assign(Object.assign({}, operation), { to: operationPayload.to, from: operationPayload.from, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'account_create':
case 'account_create_with_delegation': {
const asset = index_1.Asset.fromString(operationPayload.fee.toString());
if (asset.amount > 0)
operations.push(Object.assign(Object.assign({}, operation), { from: operationPayload.creator, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'proposal_pay': {
const asset = index_1.Asset.fromString(operationPayload.payment.toString());
if (asset.amount > 0)
operations.push(Object.assign(Object.assign({}, operation), { to: operationPayload.receiver, from: operationPayload.payer, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'fill_order': {
let asset = index_1.Asset.fromString(operationPayload.current_pays.toString());
if (asset.amount > 0)
operations.push(Object.assign(Object.assign({}, operation), { to: operationPayload.open_owner, from: operationPayload.current_owner, amount: asset.amount, currency: asset.symbol }));
asset = index_1.Asset.fromString(operationPayload.open_pays.toString());
if (asset.amount > 0)
operations.push(Object.assign(Object.assign({}, operation), { to: operationPayload.current_owner, from: operationPayload.open_owner, amount: asset.amount, currency: asset.symbol }));
break;
}
case 'proposal_fee': {
const asset = index_1.Asset.fromString(operationPayload.fee.toString());
if (asset.amount > 0)
operations.push(Object.assign(Object.assign({}, operation), { to: operationPayload.treasury, from: operationPayload.creator, amount: asset.amount, currency: asset.symbol }));
break;
}
default:
console.info(`missing ${operationType}`);
break;
}
}
let percentage;
if (startDate && percentageDuration) {
const tx = rawTransactions[rawTransactions.length - 1];
const transactionInfo = tx[1];
const date = (0, moment_1.default)(transactionInfo.timestamp + 'z').toDate();
const passedDuration = endDate.getTime() - date.getTime();
percentage = (passedDuration / percentageDuration) * 100;
}
else {
const index = lastTransaction - rawTransactions[rawTransactions.length - 1][0];
percentage = (index / lastTransaction) * 100;
}
if (feedBack)
feedBack(percentage);
start = Math.min(start - 1000, rawTransactions[0][0] - 1);
} while (start > MAX_LIMIT && !forceStop);
return operations;
}
catch (err) {
console.error('Error while fetching transactions', err);
}
return undefined;
});
exports.ExportTransactionsUtils = {
fetchTransactions,
generateCSV,
};