UNPKG

crypto-janitor

Version:

The Crypto Janitor provides a simple interface for fetching and cleaning crypto account data.

171 lines 7.05 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable max-len */ const target_types_1 = require("../target.types"); const _ = require("lodash"); /** * A Coinbase Implementation of ccxtConnection * @todo Properly parse ledger transaction and merge them with others */ class Coinbase extends target_types_1.CcxtConnection { /** * @description Create Coinbase instance * @param {any} creds - API creds of exchange */ constructor(creds) { super("coinbase", creds, { rateLimit: 100, requireSymbols: true, requireUsdValuation: false, }); } /** * @description Get corresponding coinbase account ID from symbol * @param {string} symbol - Currency symbol * @return {string} Account ID */ _getAccountIdFromSymbol(symbol) { const matches = this.accounts.filter((x) => x.currency.code === symbol); const accountId = matches[0].id; return accountId; } /** * @description Format orders * @param {any} entry - Unformatted coinbase transaction * @param {string} type - Type of transaction * @return {Transaction} Formatted transaction */ _formatLedgerEntry(entry, type) { const feeQty = entry.network && entry.network.transaction_fee ? parseFloat(entry.network.transaction_fee.amount) : 0; const feeCurrency = feeQty > 0 ? entry.network.transaction_fee.currency : "USD"; const nativeTotal = Math.abs(parseFloat(entry.native_amount.amount)); let baseQuantity = Math.abs(parseFloat(entry.amount.amount)); const price = nativeTotal / baseQuantity; baseQuantity = entry.amount.currency === feeCurrency ? baseQuantity - feeQty : baseQuantity; const feeUsdPrice = feeQty > 0 ? price : 1; const feeTotal = feeQty * feeUsdPrice; const subTotal = nativeTotal - feeTotal; const formatted = { id: entry.id, timestamp: new Date(entry.created_at), type: type, baseCurrency: entry.amount.currency, baseQuantity: baseQuantity, baseUsdPrice: subTotal / baseQuantity, feeCurrency: feeCurrency, feeQuantity: feeQty, feeUsdPrice: feeUsdPrice, feeTotal: feeTotal, subTotal: subTotal, total: nativeTotal, }; return formatted; } /** * @description Initialize coinbase and get active accounts * @override ccxtConnection.initialize * @param {boolean} forceReload - (Optional) Additional paramaters * @return {Promise<void>} */ async initialize(forceReload = false) { await super.initialize(forceReload); this.accounts = this.balances.info.data.filter((account) => account.created_at !== account.updated_at); // active account if created_at and updated_at dont match this.symbols = this.accounts.map((x) => x.currency.code); } /** * @description Fetch all account transactions (withdrawals, deposits, and orders) * @todo Paginate requests rather than just set max limit of 100 * @override ccxtConnection.getLedger * @param {string} symbol Currency symbol * @param {number} since (Optional) Timestamp to get transactions since * @param {number} limit (Optional) Max number of entries per request * @return {Promise<any>} Array of withdrawal objects */ async getLedger(symbol, since, limit = 100) { const excludeTypes = ["buy", "sell", "fiat_deposit", "fiat_withdrawal"]; const ledger = await super.getLedger(symbol, since, limit); const rawEntries = ledger .map((x) => x.info) .filter((x) => !excludeTypes.includes(x.type)); const parsedEntries = rawEntries.map((entry) => { if (entry.type === "staking-reward") { return this._formatLedgerEntry(entry, "interest-in-stake"); // staking interest } else if (entry.type === "interest") { return this._formatLedgerEntry(entry, "interest-in-account"); // account interest } else if (entry.hasOwnProperty("from") && entry.type === "send" && entry.network.status === "off_blockchain") { return this._formatLedgerEntry(entry, "reward"); // reward from coinbase earn } else if (entry.hasOwnProperty("to") || entry.type === "pro_deposit") { return this._formatLedgerEntry(entry, "send"); // crypto was sent } else if (entry.hasOwnProperty("from") || entry.type === "pro_withdrawal") { return this._formatLedgerEntry(entry, "receive"); // crypto was received } else if (entry.type === "exchange_deposit") { return this._formatLedgerEntry(entry, "withdrawal"); // crypto was withdrawn } else if (entry.type === "exchange_withdrawal") { return this._formatLedgerEntry(entry, "deposit"); // crypto was deposited } else { console.log(entry.type, entry.created_at); } return null; }); return parsedEntries; } /** * @description Fetch Coinbase Orders * @override ccxtConnection.getOrders * @param {string} symbol Currency symbol * @param {number} since (Optional) Timestamp to get transactions since * @return {Array<any>} Array of order objects */ async getOrders(symbol, since) { const accountId = this._getAccountIdFromSymbol(symbol); let trades = await Promise.all([ this.connection.fetchMyBuys(symbol, since, undefined, { accountId, }), this.connection.fetchMySells(symbol, since, undefined, { accountId, }), ]); trades = _.flatten(trades); return trades.map((trade) => this._formatOrder(trade)); } /** * @description Fetch Fetch Coinbase transactions * @override ccxtConnection.getTransactions * @param {string} symbol Currency symbol * @param {number} since (Optional) Timestamp to get transactions since * @return {any} Transactions object */ async getTransactions(symbol, since) { const reqs = [ this.getOrders(symbol, since), this.getLedger(symbol, since), ]; if (symbol === "USD") { // only get withdrawals and deposits for fiat reqs.push(this.getWithdrawals(symbol, "withdrawal", since)); reqs.push(this.getDeposits(symbol, "deposit", since)); } let results = await Promise.all(reqs); results = _.flatten(results); return _.sortBy(results, "timestamp"); } } exports.default = Coinbase; //# sourceMappingURL=coinbase.js.map