@ercworldio/blockchain-shared 1.0.17 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,12 +18,14 @@ export interface FetchPriceData {
18
18
  declare class AccountingService extends BaseErrors {
19
19
  private dbPool;
20
20
  private config;
21
+ private logger;
21
22
  constructor(dbPool: IDatabasePool, config: IConfig);
22
23
  deposit_address_exists_by_user: (user_id: number, address: string, blockchain: BlockchainType) => Promise<boolean>;
23
24
  get_crypto_withdrawal_request: (request_id: number) => Promise<WithdrawRequestDetails | null>;
24
25
  get_crypto_rate: (chain_id: ChainId) => Promise<number>;
25
26
  private fetch_crypto_rate_task;
26
27
  convert_amount_to_currency: (amount_in_source: number, source_currency: string, destination_currency: string) => Promise<number>;
28
+ private validate_currency_code;
27
29
  private convert_currency_pair_task;
28
30
  find_withdrawal_by_hash: (tx_hash: string, request_id: number) => Promise<any>;
29
31
  find_withdrawals_batch: (lookups: WithdrawalLookup[]) => Promise<any>;
@@ -1 +1 @@
1
- {"version":3,"file":"AccountingService.d.ts","sourceRoot":"","sources":["../../src/services/AccountingService.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAG9D,MAAM,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAC5E,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,qBAAqB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAElF,MAAM,WAAW,qBAAqB;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,OAAO,CAAA;CACpB;AAED,cAAM,iBAAkB,SAAQ,UAAU;IACtC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAU;gBACZ,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO;IAM3C,8BAA8B,GAAU,SAAS,MAAM,EAAE,SAAS,MAAM,EAAE,YAAY,cAAc,sBAe1G;IAEM,6BAA6B,GAAU,YAAY,MAAM,4CAc/D;IAEM,eAAe,GAAU,UAAU,OAAO,qBAQhD;IAGD,OAAO,CAAC,sBAAsB,CAoB7B;IAGM,0BAA0B,GAAU,kBAAkB,MAAM,EAAE,iBAAiB,MAAM,EAAE,sBAAsB,MAAM,qBASzH;IAED,OAAO,CAAC,0BAA0B,CAUjC;IAEM,uBAAuB,GAAU,SAAS,MAAM,EAAE,YAAY,MAAM,kBAe1E;IAEM,sBAAsB,GACzB,SAAS,gBAAgB,EAAE,kBA8B7B;IAEK,4BAA4B,GAAU,QAAO,MAAY,kBAmB/D;IAqDM,qCAAqC,GAAU,QAAO,MAAY,EAAE,kBAAiB,MAAU,kBA4DrG;CACJ;AAED,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"AccountingService.d.ts","sourceRoot":"","sources":["../../src/services/AccountingService.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAO9D,MAAM,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAC5E,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,qBAAqB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAElF,MAAM,WAAW,qBAAqB;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,OAAO,CAAA;CACpB;AAED,cAAM,iBAAkB,SAAQ,UAAU;IACtC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAAS;gBACX,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO;IAO3C,8BAA8B,GAAU,SAAS,MAAM,EAAE,SAAS,MAAM,EAAE,YAAY,cAAc,sBAe1G;IAEM,6BAA6B,GAAU,YAAY,MAAM,4CAc/D;IAEM,eAAe,GAAU,UAAU,OAAO,qBAQhD;IAGD,OAAO,CAAC,sBAAsB,CAoB7B;IAGM,0BAA0B,GAAU,kBAAkB,MAAM,EAAE,iBAAiB,MAAM,EAAE,sBAAsB,MAAM,qBAiBzH;IAED,OAAO,CAAC,sBAAsB,CAQ7B;IAED,OAAO,CAAC,0BAA0B,CAuBjC;IAEM,uBAAuB,GAAU,SAAS,MAAM,EAAE,YAAY,MAAM,kBAe1E;IAEM,sBAAsB,GACzB,SAAS,gBAAgB,EAAE,kBA8B7B;IAEK,4BAA4B,GAAU,QAAO,MAAY,kBAmB/D;IAqDM,qCAAqC,GAAU,QAAO,MAAY,EAAE,kBAAiB,MAAU,kBA4DrG;CACJ;AAED,eAAe,iBAAiB,CAAC"}
@@ -16,6 +16,9 @@ const errors_1 = __importDefault(require("../errors/errors"));
16
16
  const Wallets_1 = require("../utils/Wallets");
17
17
  const ChainManager_1 = __importDefault(require("./ChainManager"));
18
18
  const AsyncTTLCache_1 = __importDefault(require("../utils/AsyncTTLCache"));
19
+ const Logger_1 = require("../utils/Logger");
20
+ // Currency tickers are short alphanumeric codes (EUR, USD, USDT, ...); anything else is rejected before it reaches the DB.
21
+ const CURRENCY_CODE_PATTERN = /^[A-Z0-9]{2,10}$/;
19
22
  class AccountingService extends errors_1.default {
20
23
  constructor(dbPool, config) {
21
24
  super();
@@ -63,20 +66,45 @@ class AccountingService extends errors_1.default {
63
66
  return Number(result[0].fn_get_crypto_rate);
64
67
  });
65
68
  this.convert_amount_to_currency = (amount_in_source, source_currency, destination_currency) => __awaiter(this, void 0, void 0, function* () {
69
+ const source = this.validate_currency_code(source_currency, "source_currency");
70
+ const destination = this.validate_currency_code(destination_currency, "destination_currency");
71
+ if (typeof amount_in_source !== "number" || !Number.isFinite(amount_in_source)) {
72
+ this.logger.warn(`Rejected currency conversion: invalid amount`, { data: { amount_in_source: String(amount_in_source).slice(0, 200), source, destination } });
73
+ throw new Error(`Invalid amount for currency conversion`);
74
+ }
66
75
  // const unit_rate = await PriceCache.getInstance().get_rate(source_currency, destination_currency, this.convert_currency_pair_task);
67
- const key = `${source_currency.toUpperCase()}/${destination_currency.toUpperCase()}`;
68
- const unit_rate = yield AsyncTTLCache_1.default.getInstance().get_value(key, { amount_in_source, source_currency, destination_currency }, this.convert_currency_pair_task);
76
+ const key = `${source}/${destination}`;
77
+ const unit_rate = yield AsyncTTLCache_1.default.getInstance().get_value(key, { amount_in_source, source_currency: source, destination_currency: destination }, this.convert_currency_pair_task);
69
78
  return unit_rate * amount_in_source;
70
79
  });
80
+ this.validate_currency_code = (value, field) => {
81
+ const code = typeof value === "string" ? value.trim().toUpperCase() : "";
82
+ if (!CURRENCY_CODE_PATTERN.test(code)) {
83
+ // Warn goes to Elastic: an unexpected value here is either a client bug or an injection attempt.
84
+ this.logger.warn(`Rejected currency conversion: invalid ${field}`, { data: { field, value: String(value).slice(0, 200) } });
85
+ throw new Error(`Invalid ${field}`);
86
+ }
87
+ return code;
88
+ };
71
89
  this.convert_currency_pair_task = (data) => __awaiter(this, void 0, void 0, function* () {
72
90
  if (!this.dbPool.customerAppDataSource)
73
91
  throw new Error(this.NotInitializedDatabase());
74
92
  const { amount_in_source, source_currency, destination_currency } = data;
75
- const result = yield this.dbPool.customerAppDataSource.query(`
76
- SELECT accounting.fn_convert_amount_to_currency(${amount_in_source}, '${source_currency.toUpperCase()}'::text, '${destination_currency.toUpperCase()}'::text)
77
- `);
78
- if (result[0].fn_convert_amount_to_currency === null)
93
+ this.logger.info(`Fetching currency conversion from DB`, { data: { amount_in_source, source_currency, destination_currency } });
94
+ let result;
95
+ try {
96
+ result = yield this.dbPool.customerAppDataSource.query(`
97
+ SELECT accounting.fn_convert_amount_to_currency($1::numeric, $2::text, $3::text)
98
+ `, [amount_in_source, source_currency, destination_currency]);
99
+ }
100
+ catch (error) {
101
+ this.logger.error(`Currency conversion query failed`, { data: { error, amount_in_source, source_currency, destination_currency } });
102
+ throw error;
103
+ }
104
+ if (!result.length || result[0].fn_convert_amount_to_currency === null) {
105
+ this.logger.warn(`No conversion rate returned`, { data: { source_currency, destination_currency } });
79
106
  throw new Error(`Failed to get crypto rate for pair ${source_currency}/${destination_currency}`);
107
+ }
80
108
  return Number(result[0].fn_convert_amount_to_currency);
81
109
  });
82
110
  this.find_withdrawal_by_hash = (tx_hash, request_id) => __awaiter(this, void 0, void 0, function* () {
@@ -234,6 +262,7 @@ class AccountingService extends errors_1.default {
234
262
  });
235
263
  this.dbPool = dbPool;
236
264
  this.config = config;
265
+ this.logger = (0, Logger_1.createLogger)(`AccountingService`, this.config.pipelineConfig.azureAppName);
237
266
  }
238
267
  }
239
268
  exports.default = AccountingService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ercworldio/blockchain-shared",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "Shared library for blockchain projects",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",