@mojaloop/central-ledger 16.2.0 → 16.3.1-snapshot.0

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [16.3.0](https://github.com/mojaloop/central-ledger/compare/v16.2.0...v16.3.0) (2022-09-08)
6
+
7
+
8
+ ### Features
9
+
10
+ * **mojaloop/#2880:** simplify liquidity cover check and fix issue with validation (for master) ([#918](https://github.com/mojaloop/central-ledger/issues/918)) ([825faf7](https://github.com/mojaloop/central-ledger/commit/825faf7c1c918b12eddedeb97eea0a2d563457e4))
11
+
5
12
  ## [16.2.0](https://github.com/mojaloop/central-ledger/compare/v16.1.0...v16.2.0) (2022-08-15)
6
13
 
7
14
 
package/audit-ci.jsonc CHANGED
@@ -12,13 +12,13 @@
12
12
  "GHSA-282f-qqgm-c34q",
13
13
  "GHSA-6vfc-qv3f-vr6c",
14
14
  "GHSA-wc69-rhjr-hc9g",
15
+ "GHSA-f825-f98c-gj3g",
15
16
  "GHSA-g954-5hwp-pp24",
16
- "GHSA-mjxr-4v3x-q3m4",
17
17
  "GHSA-rjqq-98f6-6j3r",
18
+ "GHSA-mjxr-4v3x-q3m4",
18
19
  "GHSA-g64q-3vg8-8f93",
19
20
  "GHSA-5854-jvxx-2cg9",
20
21
  "GHSA-w5p7-h5w8-2hfq",
21
- "GHSA-p9pc-299p-vxgp",
22
- "GHSA-f825-f98c-gj3g"
22
+ "GHSA-p9pc-299p-vxgp"
23
23
  ]
24
- }
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mojaloop/central-ledger",
3
- "version": "16.2.0",
3
+ "version": "16.3.1-snapshot.0",
4
4
  "description": "Central ledger hosted by a scheme to record and settle transfers",
5
5
  "license": "Apache-2.0",
6
6
  "author": "ModusBox",
@@ -76,38 +76,38 @@
76
76
  },
77
77
  "dependencies": {
78
78
  "@hapi/good": "9.0.1",
79
- "@hapi/hapi": "20.2.2",
79
+ "@hapi/hapi": "21.0.0",
80
80
  "@hapi/inert": "7.0.0",
81
81
  "@hapi/joi": "17.1.1",
82
82
  "@hapi/vision": "7.0.0",
83
83
  "@mojaloop/central-services-database": "10.7.0",
84
- "@mojaloop/central-services-error-handling": "12.0.4",
84
+ "@mojaloop/central-services-error-handling": "12.0.5",
85
85
  "@mojaloop/central-services-health": "14.0.1",
86
- "@mojaloop/central-services-logger": "11.0.1",
86
+ "@mojaloop/central-services-logger": "11.1.0",
87
87
  "@mojaloop/central-services-metrics": "12.0.5",
88
- "@mojaloop/central-services-shared": "17.3.0",
88
+ "@mojaloop/central-services-shared": "17.3.1",
89
89
  "@mojaloop/central-services-stream": "11.0.0",
90
90
  "@mojaloop/event-sdk": "11.0.2",
91
91
  "@mojaloop/ml-number": "11.2.1",
92
92
  "@mojaloop/object-store-lib": "12.0.0",
93
93
  "@now-ims/hapi-now-auth": "2.1.0",
94
- "ajv": "8.11.0",
94
+ "ajv": "8.11.2",
95
95
  "ajv-keywords": "5.1.0",
96
96
  "base64url": "3.0.1",
97
97
  "blipp": "4.0.2",
98
98
  "catbox-memory": "4.0.1",
99
- "commander": "9.4.0",
99
+ "commander": "9.4.1",
100
100
  "cron": "2.1.0",
101
- "decimal.js": "10.4.0",
102
- "docdash": "1.2.0",
101
+ "decimal.js": "10.4.2",
102
+ "docdash": "2.0.0",
103
103
  "event-stream": "4.0.1",
104
104
  "five-bells-condition": "5.0.1",
105
105
  "glob": "8.0.3",
106
106
  "hapi-auth-basic": "5.0.0",
107
107
  "hapi-auth-bearer-token": "8.0.0",
108
- "hapi-swagger": "14.5.5",
108
+ "hapi-swagger": "15.0.0",
109
109
  "ilp-packet": "2.2.0",
110
- "knex": "2.2.0",
110
+ "knex": "2.3.0",
111
111
  "lodash": "4.17.21",
112
112
  "moment": "2.29.4",
113
113
  "rc": "1.2.8",
@@ -121,15 +121,15 @@
121
121
  "async-retry": "1.3.3",
122
122
  "audit-ci": "^6.3.0",
123
123
  "get-port": "5.1.1",
124
- "jsdoc": "3.6.11",
124
+ "jsdoc": "4.0.0",
125
125
  "jsonpath": "1.1.1",
126
- "nodemon": "2.0.19",
127
- "npm-check-updates": "16.0.5",
126
+ "nodemon": "2.0.20",
127
+ "npm-check-updates": "16.4.1",
128
128
  "nyc": "15.1.0",
129
129
  "pre-commit": "1.2.2",
130
130
  "proxyquire": "2.1.3",
131
- "replace": "^1.2.1",
132
- "sinon": "14.0.0",
131
+ "replace": "^1.2.2",
132
+ "sinon": "14.0.2",
133
133
  "standard": "17.0.0",
134
134
  "standard-version": "^9.5.0",
135
135
  "tap-spec": "^5.0.0",
@@ -86,7 +86,19 @@ const validateFspiopSourceMatchesPayer = (payload, headers) => {
86
86
  const validateFspiopSourceAndDestination = async (payload, headers) => {
87
87
  const participant = await BulkTransferService.getParticipantsById(payload.bulkTransferId)
88
88
  const matchedPayee = (headers && headers[Enum.Http.Headers.FSPIOP.SOURCE] === participant.payeeFsp)
89
- const matchedPayer = (headers && headers[Enum.Http.Headers.FSPIOP.DESTINATION] === participant.payerFsp)
89
+ const matchedPayer = (
90
+ headers &&
91
+ (
92
+ (headers[Enum.Http.Headers.FSPIOP.DESTINATION] === participant.payerFsp) ||
93
+ // The following was added for fix(mojaloop/##3024): [core bulk] POST /bulkTransfers from Switch --> PayeeFSP to use Switch as fspiop-source - https://github.com/mojaloop/project/issues/3024
94
+ // Notes:
95
+ // Due to the Bulk [Design Considerations](https://docs.mojaloop.io/technical/central-bulk-transfers/#_2-design-considerations),
96
+ // it is possible that the Switch may send a POST Request to the Payer with the Destination Header containing "Switch",
97
+ // and the Payee thus responding with a PUT Callback Destination containing the same value.
98
+ (headers[Enum.Http.Headers.FSPIOP.DESTINATION] === Enum.Http.Headers.FSPIOP.SWITCH.value)
99
+ )
100
+ )
101
+
90
102
  if (!matchedPayee) {
91
103
  reasons.push(
92
104
  ErrorHandler.Factory.createFSPIOPError(
@@ -324,6 +324,14 @@ const fulfil = async (error, messages) => {
324
324
  const transfer = await TransferService.getById(transferId)
325
325
  const transferStateEnum = transfer && transfer.transferStateEnumeration
326
326
 
327
+ // List of valid actions that Source & Destination headers should be checked
328
+ const validActionsForRouteValidations = [
329
+ TransferEventAction.COMMIT,
330
+ TransferEventAction.RESERVE,
331
+ TransferEventAction.REJECT,
332
+ TransferEventAction.ABORT
333
+ ]
334
+
327
335
  if (!transfer) {
328
336
  Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, `callbackInternalServerErrorNotFound--${actionLetter}1`))
329
337
  const fspiopError = ErrorHandler.Factory.createInternalServerFSPIOPError('transfer not found')
@@ -337,7 +345,13 @@ const fulfil = async (error, messages) => {
337
345
  throw fspiopError
338
346
 
339
347
  // Lets validate FSPIOP Source & Destination Headers
340
- } else if ((headers[Enum.Http.Headers.FSPIOP.SOURCE] && (headers[Enum.Http.Headers.FSPIOP.SOURCE].toLowerCase() !== transfer.payeeFsp.toLowerCase())) || (headers[Enum.Http.Headers.FSPIOP.DESTINATION] && (headers[Enum.Http.Headers.FSPIOP.DESTINATION].toLowerCase() !== transfer.payerFsp.toLowerCase()))) {
348
+ } else if (
349
+ validActionsForRouteValidations.includes(action) && // Lets only check headers for specific actions that need checking (i.e. bulk should not since its already done elsewhere)
350
+ (
351
+ (headers[Enum.Http.Headers.FSPIOP.SOURCE] && (headers[Enum.Http.Headers.FSPIOP.SOURCE].toLowerCase() !== transfer.payeeFsp.toLowerCase())) ||
352
+ (headers[Enum.Http.Headers.FSPIOP.DESTINATION] && (headers[Enum.Http.Headers.FSPIOP.DESTINATION].toLowerCase() !== transfer.payerFsp.toLowerCase()))
353
+ )
354
+ ) {
341
355
  /**
342
356
  * If fulfilment request is coming from a source not matching transfer payee fsp or destination not matching transfer payer fsp,
343
357
  */
@@ -160,18 +160,11 @@ const prepareChangeParticipantPositionTransaction = async (transferList) => {
160
160
  ['success', 'queryName']
161
161
  ).startTimer()
162
162
  const participantLimit = await participantFacade.getParticipantLimitByParticipantCurrencyLimit(participantCurrency.participantId, participantCurrency.currencyId, Enum.Accounts.LedgerAccountType.POSITION, Enum.Accounts.ParticipantLimitType.NET_DEBIT_CAP)
163
- // Calculate liquidity cover as per story OTC-651
164
- let liquidityCover
165
- let payerLimit
166
- if (settlementModel.settlementDelayId === Enum.Settlements.SettlementDelay.IMMEDIATE) {
167
- liquidityCover = new MLNumber(settlementParticipantPosition.value).add(new MLNumber(participantLimit.value))
168
- payerLimit = new MLNumber(participantLimit.value)
169
- } else {
170
- liquidityCover = new MLNumber(settlementParticipantPosition.value).multiply(-1)
171
- payerLimit = new MLNumber(participantLimit.value)
172
- }
173
- let availablePositionBasedOnLiquidityCover = liquidityCover.subtract(effectivePosition).toFixed(Config.AMOUNT.SCALE)
174
- let availablePositionBasedOnPayerLimit = payerLimit.subtract(effectivePosition).toFixed(Config.AMOUNT.SCALE)
163
+
164
+ const liquidityCover = new MLNumber(settlementParticipantPosition.value).multiply(-1)
165
+ const payerLimit = new MLNumber(participantLimit.value)
166
+ const availablePositionBasedOnLiquidityCover = liquidityCover.subtract(effectivePosition).toFixed(Config.AMOUNT.SCALE)
167
+ const availablePositionBasedOnPayerLimit = payerLimit.subtract(effectivePosition).toFixed(Config.AMOUNT.SCALE)
175
168
  /* Validate entire batch if availablePosition >= sumTransfersInBatch - the impact is that applying per transfer rules would require to be handled differently
176
169
  since further rules are expected we do not do this at this point
177
170
  As we enter this next step the order in which the transfer is processed against the Position is critical.
@@ -192,8 +185,6 @@ const prepareChangeParticipantPositionTransaction = async (transferList) => {
192
185
  reservedTransfers[transferId].fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PAYER_LIMIT_ERROR, null, null, null, rawMessage.value.content.payload.extensionList)
193
186
  rawMessage.value.content.payload = reservedTransfers[transferId].fspiopError.toApiErrorObject(Config.ERROR_HANDLING)
194
187
  } else {
195
- availablePositionBasedOnLiquidityCover = new MLNumber(availablePositionBasedOnLiquidityCover).subtract(transferAmount).toFixed(Config.AMOUNT.SCALE)
196
- availablePositionBasedOnPayerLimit = new MLNumber(availablePositionBasedOnPayerLimit).subtract(transferAmount).toFixed(Config.AMOUNT.SCALE)
197
188
  transferState.transferStateId = Enum.Transfers.TransferState.RESERVED
198
189
  sumReserved = new MLNumber(sumReserved).add(transferAmount).toFixed(Config.AMOUNT.SCALE) /* actually used */
199
190
  }
@@ -212,7 +203,7 @@ const prepareChangeParticipantPositionTransaction = async (transferList) => {
212
203
  So the position moves forward by the sum of the transfers actually reserved (sumReserved)
213
204
  and the reserved amount is cleared of the we reserved in the first instance (sumTransfersInBatch)
214
205
  */
215
- const processedPositionValue = new MLNumber(initialParticipantPosition.value).add(sumReserved)
206
+ const processedPositionValue = currentPosition.add(sumReserved)
216
207
  await knex('participantPosition').transacting(trx).where({ participantPositionId: initialParticipantPosition.participantPositionId }).update({
217
208
  value: processedPositionValue.toFixed(Config.AMOUNT.SCALE),
218
209
  reservedValue: new MLNumber(initialParticipantPosition.reservedValue).subtract(sumTransfersInBatch).toFixed(Config.AMOUNT.SCALE),