@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.
|
|
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": "
|
|
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.
|
|
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
|
|
86
|
+
"@mojaloop/central-services-logger": "11.1.0",
|
|
87
87
|
"@mojaloop/central-services-metrics": "12.0.5",
|
|
88
|
-
"@mojaloop/central-services-shared": "17.3.
|
|
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.
|
|
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.
|
|
99
|
+
"commander": "9.4.1",
|
|
100
100
|
"cron": "2.1.0",
|
|
101
|
-
"decimal.js": "10.4.
|
|
102
|
-
"docdash": "
|
|
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": "
|
|
108
|
+
"hapi-swagger": "15.0.0",
|
|
109
109
|
"ilp-packet": "2.2.0",
|
|
110
|
-
"knex": "2.
|
|
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": "
|
|
124
|
+
"jsdoc": "4.0.0",
|
|
125
125
|
"jsonpath": "1.1.1",
|
|
126
|
-
"nodemon": "2.0.
|
|
127
|
-
"npm-check-updates": "16.
|
|
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.
|
|
132
|
-
"sinon": "14.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 = (
|
|
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 (
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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 =
|
|
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),
|