@mojaloop/central-ledger 19.14.0 → 20.1.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.
Files changed (394) hide show
  1. package/.grype.yaml +3 -0
  2. package/.license-scanner.json +16 -0
  3. package/.ncurc.yaml +19 -13
  4. package/.nvmrc +1 -1
  5. package/.nycrc.yml +14 -2
  6. package/CHANGELOG.md +51 -0
  7. package/Dockerfile +13 -10
  8. package/README.md +39 -89
  9. package/audit-ci.jsonc +1 -1
  10. package/config/default.json +60 -3
  11. package/config/deprecated.default-settlement.json +160 -0
  12. package/docker/ml-api-adapter/default.json +28 -0
  13. package/docker-compose.yml +6 -0
  14. package/nodemon.json +6 -0
  15. package/package.json +128 -64
  16. package/{sbom-v19.13.2.csv → sbom-v20.0.0.csv} +886 -736
  17. package/scripts/_wait4_all.js +5 -5
  18. package/scripts/transferSettlementTemp/interchangeFeeCalculation.js +51 -0
  19. package/src/api/index.ts +30 -0
  20. package/src/api/interface/swagger.json +2249 -2054
  21. package/src/api/participants/routes.js +1 -1
  22. package/src/api/root/handler.int.ts +55 -0
  23. package/src/api/routes.js +7 -6
  24. package/src/api/server.ts +27 -0
  25. package/src/api/server.unit.ts +16 -0
  26. package/src/api/settlementModels/routes.js +4 -4
  27. package/src/domain/participant/index.d.ts +47 -0
  28. package/src/domain/participant/index.int.ts +724 -0
  29. package/src/domain/participant/index.js +4 -5
  30. package/src/domain/position/fx-prepare.js +1 -1
  31. package/src/domain/position/fx-timeout-reserved.js +6 -0
  32. package/src/domain/position/prepare.js +1 -1
  33. package/src/handlers/admin/handler.js +1 -1
  34. package/src/handlers/index.js +30 -0
  35. package/src/handlers/positions/handler.js +0 -2
  36. package/src/handlers/positions/handlerBatch.js +5 -5
  37. package/src/handlers/register.js +44 -29
  38. package/src/handlers/timeouts/handler.js +1 -4
  39. package/src/handlers/transfers/fx-abort.int.ts +209 -0
  40. package/src/handlers/transfers/fx-handlers.int.ts +275 -0
  41. package/src/handlers/transfers/fx-timeout.int.ts +284 -0
  42. package/src/handlers/transfers/handler.js +1 -3
  43. package/src/handlers/transfers/handlers.int.ts +538 -0
  44. package/src/handlers/transfers/prepare.int.ts +1283 -0
  45. package/src/handlers/transfers/prepare.js +2 -2
  46. package/src/knexfile.js +19 -0
  47. package/src/lib/cache.js +1 -1
  48. package/src/lib/config/index.ts +60 -0
  49. package/src/lib/config/resolver.ts +231 -0
  50. package/src/lib/config/resolver.unit.ts +72 -0
  51. package/src/lib/config/types.ts +372 -0
  52. package/src/lib/config/util.ts +523 -0
  53. package/src/lib/config/util.unit.ts +825 -0
  54. package/src/lib/migrator.js +3 -3
  55. package/src/lib/proxyCache.js +3 -3
  56. package/{migrations → src/migrations}/100100_event.js +1 -1
  57. package/{migrations → src/migrations}/110100_contactType.js +1 -1
  58. package/{migrations → src/migrations}/110200_currency.js +1 -1
  59. package/{migrations → src/migrations}/110201_currency-scale.js +1 -1
  60. package/{migrations → src/migrations}/110300_endpointType.js +1 -1
  61. package/{migrations → src/migrations}/110400_ledgerEntryType.js +1 -1
  62. package/{migrations → src/migrations}/110450_ledgerAccountType.js +1 -1
  63. package/{migrations → src/migrations}/110500_participantLimitType.js +1 -1
  64. package/{migrations → src/migrations}/110600_transferParticipantRoleType.js +1 -1
  65. package/{migrations → src/migrations}/110700_transferState.js +1 -1
  66. package/{migrations → src/migrations}/110900_settlementState.js +1 -1
  67. package/{migrations → src/migrations}/112000_bulkTransferState.js +1 -1
  68. package/{migrations → src/migrations}/112100_bulkProcessingState.js +1 -1
  69. package/{migrations → src/migrations}/200100_participant.js +1 -1
  70. package/{migrations → src/migrations}/200200_participantContact.js +1 -1
  71. package/{migrations → src/migrations}/200300_participantEndpoint.js +1 -1
  72. package/{migrations → src/migrations}/200400_participantParty.js +1 -1
  73. package/{migrations → src/migrations}/200600_token.js +1 -1
  74. package/{migrations → src/migrations}/200601_token-indexes.js +1 -1
  75. package/{migrations → src/migrations}/300100_transferDuplicateCheck.js +2 -2
  76. package/{migrations → src/migrations}/300150_bulkTransferDuplicateCheck.js +2 -2
  77. package/{migrations → src/migrations}/300200_transfer.js +2 -2
  78. package/{migrations → src/migrations}/300202_transfer-decimal184.js +1 -1
  79. package/{migrations → src/migrations}/300250_bulkTransfer.js +2 -3
  80. package/{migrations → src/migrations}/300275_bulkTransferAssociation.js +2 -3
  81. package/{migrations → src/migrations}/300300_ilpPacket.js +1 -1
  82. package/{migrations → src/migrations}/300400_transferStateChange.js +1 -1
  83. package/{migrations → src/migrations}/300450_bulkTransferStateChange.js +1 -1
  84. package/{migrations → src/migrations}/300500_segment.js +1 -1
  85. package/{migrations → src/migrations}/310100_participantCurrency.js +1 -1
  86. package/{migrations → src/migrations}/310200_transferParticipant.js +1 -1
  87. package/{migrations → src/migrations}/310202_transferParticipant-decimal184.js +1 -1
  88. package/{migrations → src/migrations}/310204_transferParticipant-participantId.js +2 -2
  89. package/{migrations → src/migrations}/310300_participantPosition.js +1 -1
  90. package/{migrations → src/migrations}/310302_participantPosition-decimal184.js +1 -1
  91. package/{migrations → src/migrations}/310400_participantPositionChange.js +1 -1
  92. package/{migrations → src/migrations}/310402_participantPositionChange-decimal184.js +1 -1
  93. package/{migrations → src/migrations}/310403_participantPositionChange-participantCurrencyId.js +2 -2
  94. package/{migrations → src/migrations}/310404_participantPositionChange-change.js +2 -2
  95. package/{migrations → src/migrations}/310500_participantLimit.js +1 -1
  96. package/{migrations → src/migrations}/310502_participantLimit-decimal184.js +1 -1
  97. package/{migrations → src/migrations}/400100_settlementWindow.js +1 -1
  98. package/{migrations → src/migrations}/400200_settlement.js +1 -1
  99. package/{migrations → src/migrations}/400300_settlementSettlementWindow.js +1 -1
  100. package/{migrations → src/migrations}/400301_settlementSettlementWindow-indexes.js +0 -1
  101. package/{migrations → src/migrations}/400400_settlementWindowStateChange.js +1 -1
  102. package/{migrations → src/migrations}/400500_settlementTransferParticipant.js +1 -1
  103. package/{migrations → src/migrations}/400502_settlementTransferParticipant-decimal184.js +1 -1
  104. package/{migrations → src/migrations}/400600_settlementParticipantCurrency.js +1 -1
  105. package/{migrations → src/migrations}/400602_settlementParticipantCurrency-decimal184.js +1 -1
  106. package/{migrations → src/migrations}/400700_settlementParticipantCurrencyStateChange.js +1 -1
  107. package/{migrations → src/migrations}/400800_settlementStateChange.js +1 -1
  108. package/{migrations → src/migrations}/400900_settlementWindowContent.js +1 -1
  109. package/{migrations → src/migrations}/401000_settlementWindowContentStateChange.js +1 -1
  110. package/{migrations → src/migrations}/401001_settlementWindowContentStateChange-indexes.js +6 -6
  111. package/{migrations → src/migrations}/401200_settlementContentAggregation.js +1 -1
  112. package/{migrations → src/migrations}/401300_settlementModel.js +1 -1
  113. package/{migrations → src/migrations}/410100_transferFulfilmentDuplicateCheck.js +1 -1
  114. package/{migrations → src/migrations}/410102_transferFulfilmentDuplicateCheck-dropForeignTransferId.js +1 -1
  115. package/{migrations → src/migrations}/410103_transferFulfilmentDuplicateCheck-hashNullable.js +1 -1
  116. package/{migrations → src/migrations}/410200_transferFulfilment.js +1 -1
  117. package/{migrations → src/migrations}/410202_transferFulfilment-ilpFulfilment.js +1 -1
  118. package/{migrations → src/migrations}/410203_transferFulfilment-foreignTransferFulfilmentId.js +1 -1
  119. package/{migrations → src/migrations}/410240_bulkTransferFulfilmentDuplicateCheck.js +1 -1
  120. package/{migrations → src/migrations}/410250_bulkTransferFulfilment.js +1 -1
  121. package/{migrations → src/migrations}/410300_transferExtension.js +1 -1
  122. package/{migrations → src/migrations}/410302_transferExtension-transferErrorId.js +1 -1
  123. package/{migrations → src/migrations}/410350_bulkTransferExtension.js +1 -1
  124. package/{migrations → src/migrations}/410400_transferTimeout.js +1 -1
  125. package/{migrations → src/migrations}/410450_transferErrorDuplicateCheck.js +1 -1
  126. package/{migrations → src/migrations}/410500_transferError.js +1 -1
  127. package/{migrations → src/migrations}/410502_transferError-foreignTransferErrorDuplicateCheckId.js +1 -1
  128. package/{migrations → src/migrations}/410550_bulkTransferError.js +1 -1
  129. package/{migrations → src/migrations}/410600_expiringTransfer.js +1 -1
  130. package/{migrations → src/migrations}/500401_quote-hotfix-2719.js +8 -8
  131. package/{migrations → src/migrations}/500501_feature-fixSubIdRef.js +12 -12
  132. package/{migrations → src/migrations}/500601_party-2480.js +3 -3
  133. package/{migrations → src/migrations}/501001_quoteExtension-quote-service-174.js +1 -2
  134. package/{migrations → src/migrations}/501002_quoteExtension-2522.js +3 -3
  135. package/{migrations → src/migrations}/600010_fxTransferType.js +1 -1
  136. package/{migrations → src/migrations}/600012_fxParticipantCurrencyType.js +1 -1
  137. package/{migrations → src/migrations}/600100_fxTransferDuplicateCheck.js +2 -2
  138. package/{migrations → src/migrations}/600110_fxTransferErrorDuplicateCheck.js.js +1 -1
  139. package/{migrations → src/migrations}/600200_fxTransfer.js +2 -2
  140. package/{migrations → src/migrations}/600400_fxTransferStateChange.js +1 -1
  141. package/{migrations → src/migrations}/600501_fxWatchList.js +2 -2
  142. package/{migrations → src/migrations}/600600_fxTransferFulfilmentDuplicateCheck.js +1 -1
  143. package/{migrations → src/migrations}/600700_fxTransferFulfilment.js +1 -1
  144. package/{migrations → src/migrations}/600800_fxTransferExtension.js +1 -1
  145. package/{migrations → src/migrations}/601400_fxTransferTimeout.js +1 -1
  146. package/{migrations → src/migrations}/601500_fxTransferError.js +1 -1
  147. package/{migrations → src/migrations}/610200_fxTransferParticipant.js +1 -1
  148. package/{migrations → src/migrations}/610202_fxTransferParticipant-participantId.js +2 -2
  149. package/{migrations → src/migrations}/610403_participantPositionChange-fxTransfer.js +1 -1
  150. package/{migrations → src/migrations}/800100_quotePartyView.js +1 -1
  151. package/{migrations → src/migrations}/800101_feature-fixSubIdRef.js +1 -1
  152. package/{migrations → src/migrations}/800200_quoteView.js +1 -1
  153. package/{migrations → src/migrations}/800300_quoteResponseView.js +1 -1
  154. package/{migrations → src/migrations}/900100_foreign-keys.js +18 -18
  155. package/{migrations → src/migrations}/900101_foreign-keys.js +6 -6
  156. package/{migrations → src/migrations}/910100_feature904DDL.js +7 -7
  157. package/{migrations → src/migrations}/910101_feature904DataMigration.js +1 -1
  158. package/{migrations → src/migrations}/910102_feature949DataMigration.js +1 -1
  159. package/{migrations → src/migrations}/910103_feature1093SettlementByCurrency.js +3 -3
  160. package/{migrations → src/migrations}/940101_quotePartyIdInfoExtension-2522.js +25 -25
  161. package/{migrations → src/migrations}/950101_transferParticipantStateChange.js +2 -2
  162. package/{migrations → src/migrations}/950102_settlementModel-adjustPosition.js +2 -2
  163. package/{migrations → src/migrations}/950103_dropTransferParticipantStateChange.js +3 -3
  164. package/{migrations → src/migrations}/950104_settlementModel-settlementAccountTypeId.js +3 -3
  165. package/src/migrations/950107_settlementWindowContent_foreign_settlementModel.js +63 -0
  166. package/{migrations → src/migrations}/950108_participantProxy.js +1 -2
  167. package/{migrations → src/migrations}/950120_fxQuoteConversionTerms_sourceAmount_nullable.js +1 -1
  168. package/{migrations → src/migrations}/960100_create_externalParticipant.js +2 -2
  169. package/{migrations → src/migrations}/960110_alter_transferParticipant__addFiled_externalParticipantId.js +2 -2
  170. package/{migrations → src/migrations}/961001_transferForwarded.js +1 -1
  171. package/{migrations → src/migrations}/961002_fxTransferForwarded.js +1 -1
  172. package/src/models/participant/externalParticipant.int.ts +85 -0
  173. package/src/models/participant/facade.js +4 -2
  174. package/src/models/participant/participantCurrencyCached.js +1 -1
  175. package/src/models/position/facade.js +8 -2
  176. package/src/models/transfer/facade.int.ts +139 -0
  177. package/src/models/transfer/facade.js +8 -3
  178. package/src/models/transfer/transferDuplicateCheck.js +2 -2
  179. package/src/models/transfer/transferError.int.ts +112 -0
  180. package/src/models/transfer/transferExtension.int.ts +137 -0
  181. package/src/models/transfer/transferStateChange.int.ts +117 -0
  182. package/{seeds → src/seeds}/participant.js +1 -1
  183. package/{seeds → src/seeds}/settlementInterchange.js +1 -0
  184. package/src/settlement/api/handlerRoutes.js +71 -0
  185. package/src/settlement/api/handlers/health.js +10 -0
  186. package/src/settlement/api/handlers/index.js +57 -0
  187. package/src/settlement/api/handlers/settlementWindows/{id}.js +103 -0
  188. package/src/settlement/api/handlers/settlementWindows.js +77 -0
  189. package/src/settlement/api/handlers/settlements/{id}.js +133 -0
  190. package/src/settlement/api/handlers/settlements/{sid}/participants/{pid}/accounts/{aid}.js +127 -0
  191. package/src/settlement/api/handlers/settlements/{sid}/participants/{pid}.js +127 -0
  192. package/src/settlement/api/handlers/settlements.js +114 -0
  193. package/src/settlement/api/openapiRouting.js +87 -0
  194. package/src/settlement/api/routes.js +176 -0
  195. package/src/settlement/domain/rules/index.js +46 -0
  196. package/src/settlement/domain/settlement/index.js +405 -0
  197. package/src/settlement/domain/settlementWindow/index.js +117 -0
  198. package/src/settlement/domain/transactions/index.js +83 -0
  199. package/src/settlement/domain/transferSettlement/index.js +57 -0
  200. package/src/settlement/handlers/deferredSettlement/handler.js +180 -0
  201. package/src/settlement/handlers/grossSettlement/handler.js +180 -0
  202. package/src/settlement/handlers/index.js +101 -0
  203. package/src/settlement/handlers/register.js +92 -0
  204. package/src/settlement/handlers/rules/handler.js +164 -0
  205. package/src/settlement/interface/swagger-handler.json +34 -0
  206. package/src/settlement/interface/swagger.json +1560 -0
  207. package/src/settlement/lib/db.js +32 -0
  208. package/src/settlement/lib/kafka/index.js +41 -0
  209. package/src/settlement/lib/kafka/producer.js +142 -0
  210. package/src/settlement/lib/scriptEngine.js +99 -0
  211. package/src/settlement/lib/scriptsLoader.js +175 -0
  212. package/src/settlement/lib/utility.js +243 -0
  213. package/src/settlement/models/ilpPackets/ilpPacket.js +42 -0
  214. package/src/settlement/models/lib/enums.js +192 -0
  215. package/src/settlement/models/misc/migrationLock.js +53 -0
  216. package/src/settlement/models/settlement/facade.js +1652 -0
  217. package/src/settlement/models/settlement/index.js +55 -0
  218. package/src/settlement/models/settlement/participantCurrency.js +48 -0
  219. package/src/settlement/models/settlement/settlement.js +49 -0
  220. package/src/settlement/models/settlement/settlementModel.js +44 -0
  221. package/src/settlement/models/settlement/settlementParticipantCurrency.js +61 -0
  222. package/src/settlement/models/settlement/settlementStateChange.js +44 -0
  223. package/src/settlement/models/settlement/settlementTransferParticipant.js +46 -0
  224. package/src/settlement/models/settlementWindow/facade.js +345 -0
  225. package/src/settlement/models/settlementWindow/index.js +47 -0
  226. package/src/settlement/models/settlementWindow/settlementWindowStateChange.js +55 -0
  227. package/src/settlement/models/settlementWindowContent/facade.js +79 -0
  228. package/src/settlement/models/settlementWindowContent/index.js +40 -0
  229. package/src/settlement/models/settlementWindowContent/settlementWindowContentStateChange.js +53 -0
  230. package/src/settlement/models/transferSettlement/facade.js +363 -0
  231. package/src/settlement/models/transferSettlement/index.js +42 -0
  232. package/src/settlement/shared/logger/index.js +7 -0
  233. package/src/settlement/shared/plugins.js +88 -0
  234. package/src/settlement/shared/setup.js +224 -0
  235. package/src/settlement/utils/truthyProperty.js +37 -0
  236. package/src/shared/legacyUtilShim.js +20 -0
  237. package/src/shared/plugins.js +3 -3
  238. package/src/shared/results.ts +22 -0
  239. package/src/shared/results.unit.ts +38 -0
  240. package/src/shared/setup.js +14 -1
  241. package/src/testing/api-helpers.ts +1222 -0
  242. package/src/testing/exec-async.ts +67 -0
  243. package/src/testing/harness.snapshot.sql +3895 -0
  244. package/src/testing/harness.test.ts +15 -0
  245. package/src/testing/harness.ts +1160 -0
  246. package/src/testing/kafka.ts +221 -0
  247. package/src/testing/prng.ts +82 -0
  248. package/src/testing/rdkafka.test.ts +263 -0
  249. package/src/testing/run.ts +559 -0
  250. package/src/testing/snapshot.test.ts +92 -0
  251. package/src/testing/snapshot.ts +549 -0
  252. package/src/testing/tap-stream.ts +164 -0
  253. package/src/testing/types.ts +95 -0
  254. package/src/testing/util.ts +333 -0
  255. package/src/types/central-services-error-handling.d.ts +72 -0
  256. package/src/types/central-services-stream.d.ts +148 -0
  257. package/test-integration.Dockerfile +0 -2
  258. package/test.Dockerfile +0 -2
  259. package/tsconfig.json +40 -0
  260. package/config/knexfile.js +0 -19
  261. package/migrations/950107_settlementWindowContent_foreign_settlementModel.js +0 -63
  262. package/src/api/index.js +0 -16
  263. package/src/lib/config.js +0 -81
  264. /package/{migrations → src/migrations}/110101_contactType-indexes.js +0 -0
  265. /package/{migrations → src/migrations}/110301_endpointType-indexes.js +0 -0
  266. /package/{migrations → src/migrations}/110401_ledgerEntryType-indexes.js +0 -0
  267. /package/{migrations → src/migrations}/110451_ledgerAccountType-indexes.js +0 -0
  268. /package/{migrations → src/migrations}/110501_participantLimitType-indexes.js +0 -0
  269. /package/{migrations → src/migrations}/110601_transferParticipantRoleType-indexes.js +0 -0
  270. /package/{migrations → src/migrations}/110800_settlementWindowState.js +0 -0
  271. /package/{migrations → src/migrations}/111000_amountType.js +0 -0
  272. /package/{migrations → src/migrations}/111001_amountType-indexes.js +0 -0
  273. /package/{migrations → src/migrations}/111100_balanceOfPayments.js +0 -0
  274. /package/{migrations → src/migrations}/111101_balanceOfPayments-indexes.js +0 -0
  275. /package/{migrations → src/migrations}/111200_partyIdentifierType.js +0 -0
  276. /package/{migrations → src/migrations}/111201_partyIdentifierType-indexes.js +0 -0
  277. /package/{migrations → src/migrations}/111300_partyType.js +0 -0
  278. /package/{migrations → src/migrations}/111301_partyType-indexes.js +0 -0
  279. /package/{migrations → src/migrations}/111400_quoteDuplicateCheck.js +0 -0
  280. /package/{migrations → src/migrations}/111500_transactionInitiator.js +0 -0
  281. /package/{migrations → src/migrations}/111501_transactionInitiator-indexes.js +0 -0
  282. /package/{migrations → src/migrations}/111600_transactionInitiatorType.js +0 -0
  283. /package/{migrations → src/migrations}/111601_transactionInitiatorType-indexes.js +0 -0
  284. /package/{migrations → src/migrations}/111700_settlementDelay.js +0 -0
  285. /package/{migrations → src/migrations}/111701_settlementDelay-indexes.js +0 -0
  286. /package/{migrations → src/migrations}/111800_settlementInterchange.js +0 -0
  287. /package/{migrations → src/migrations}/111801_settlementInterchange-indexes.js +0 -0
  288. /package/{migrations → src/migrations}/111900_settlementGranularity.js +0 -0
  289. /package/{migrations → src/migrations}/111901_settlementGranularity-indexes.js +0 -0
  290. /package/{migrations → src/migrations}/112101_bulkProcessingState-indexes.js +0 -0
  291. /package/{migrations → src/migrations}/200101_participant-indexes.js +0 -0
  292. /package/{migrations → src/migrations}/200201_participantContact-indexes.js +0 -0
  293. /package/{migrations → src/migrations}/200301_participantEndpoint-indexes.js +0 -0
  294. /package/{migrations → src/migrations}/200401_participantParty-indexes.js +0 -0
  295. /package/{migrations → src/migrations}/300201_transfer-indexes.js +0 -0
  296. /package/{migrations → src/migrations}/300251_bulkTransfer-indexes.js +0 -0
  297. /package/{migrations → src/migrations}/300276_bulkTransferAssociation-indexes.js +0 -0
  298. /package/{migrations → src/migrations}/300401_transferStateChange-indexes.js +0 -0
  299. /package/{migrations → src/migrations}/300451_bulkTransferStateChange-indexes.js +0 -0
  300. /package/{migrations → src/migrations}/300501_segment-indexes.js +0 -0
  301. /package/{migrations → src/migrations}/310101_participantCurrency-indexes.js +0 -0
  302. /package/{migrations → src/migrations}/310201_transferParticipant-indexes.js +0 -0
  303. /package/{migrations → src/migrations}/310203_transferParticipant-indexes.js +0 -0
  304. /package/{migrations → src/migrations}/310301_participantPosition-indexes.js +0 -0
  305. /package/{migrations → src/migrations}/310401_participantPositionChange-indexes.js +0 -0
  306. /package/{migrations → src/migrations}/310405_participantPositionChange-positionChange.js +0 -0
  307. /package/{migrations → src/migrations}/310406_participantPositionChange-positionChange-revert.js +0 -0
  308. /package/{migrations → src/migrations}/310501_participantLimit-indexes.js +0 -0
  309. /package/{migrations → src/migrations}/310503_participantLimit-indexes-composite.js +0 -0
  310. /package/{migrations → src/migrations}/400401_settlmentWindowStateChange-indexes.js +0 -0
  311. /package/{migrations → src/migrations}/400501_settlementTransferParticipant-indexes.js +0 -0
  312. /package/{migrations → src/migrations}/400601_settlementParticipantCurrency-indexes.js +0 -0
  313. /package/{migrations → src/migrations}/400701_settlementParticipantCurrencyStateChange-indexes.js +0 -0
  314. /package/{migrations → src/migrations}/400801_settlementStateChange-indexes.js +0 -0
  315. /package/{migrations → src/migrations}/401002_settlementWindowContent-indexes.js +0 -0
  316. /package/{migrations → src/migrations}/401201_settlementContentAggregation-indexes.js +0 -0
  317. /package/{migrations → src/migrations}/401301_settlementModel-indexes.js +0 -0
  318. /package/{migrations → src/migrations}/410101_transferFulfilmentDuplicateCheck-indexes.js +0 -0
  319. /package/{migrations → src/migrations}/410201_transferFulfilment-indexes.js +0 -0
  320. /package/{migrations → src/migrations}/410301_transferExtension-indexes.js +0 -0
  321. /package/{migrations → src/migrations}/410351_bulkTransferExtension-indexes.js +0 -0
  322. /package/{migrations → src/migrations}/410401_transferTimeout-indexes.js +0 -0
  323. /package/{migrations → src/migrations}/410501_transferError-indexes.js +0 -0
  324. /package/{migrations → src/migrations}/410551_bulkTransferError-indexes.js +0 -0
  325. /package/{migrations → src/migrations}/410601_expiringTransfer-indexes.js +0 -0
  326. /package/{migrations → src/migrations}/500100_transactionReference.js +0 -0
  327. /package/{migrations → src/migrations}/500101_transactionReference-indexes.js +0 -0
  328. /package/{migrations → src/migrations}/500200_transactionScenario.js +0 -0
  329. /package/{migrations → src/migrations}/500201_transactionScenario-indexes.js +0 -0
  330. /package/{migrations → src/migrations}/500300_transactionSubScenario.js +0 -0
  331. /package/{migrations → src/migrations}/500400_quote.js +0 -0
  332. /package/{migrations → src/migrations}/500500_quoteParty.js +0 -0
  333. /package/{migrations → src/migrations}/500600_party.js +0 -0
  334. /package/{migrations → src/migrations}/500700_quoteResponse.js +0 -0
  335. /package/{migrations → src/migrations}/500800_quoteResponseIlpPacket.js +0 -0
  336. /package/{migrations → src/migrations}/500900_geoCode.js +0 -0
  337. /package/{migrations → src/migrations}/501000_quoteExtension.js +0 -0
  338. /package/{migrations → src/migrations}/501100_quoteResponseDuplicateCheck.js +0 -0
  339. /package/{migrations → src/migrations}/501200_quoteError.js +0 -0
  340. /package/{migrations → src/migrations}/501300_transferRules.js +0 -0
  341. /package/{migrations → src/migrations}/600011_fxTransferType-indexes.js +0 -0
  342. /package/{migrations → src/migrations}/600013_fxParticipantCurrencyType-indexes.js +0 -0
  343. /package/{migrations → src/migrations}/600201_fxTransfer-indexes.js +0 -0
  344. /package/{migrations → src/migrations}/600401_fxTransferStateChange-indexes.js +0 -0
  345. /package/{migrations → src/migrations}/600502_fxWatchList-indexes.js +0 -0
  346. /package/{migrations → src/migrations}/600601_fxTransferFulfilmentDuplicateCheck-indexes.js +0 -0
  347. /package/{migrations → src/migrations}/600701_fxTransferFulfilment-indexes.js +0 -0
  348. /package/{migrations → src/migrations}/601401_fxTransferTimeout-indexes.js +0 -0
  349. /package/{migrations → src/migrations}/601501_fxTransferError-indexes.js +0 -0
  350. /package/{migrations → src/migrations}/610201_fxTransferParticipant-indexes.js +0 -0
  351. /package/{migrations → src/migrations}/910102_hotfix954.js +0 -0
  352. /package/{migrations → src/migrations}/940100_quotePartyIdInfoExtension.js +0 -0
  353. /package/{migrations → src/migrations}/950100_settlementContentAggregation-decimal184.js +0 -0
  354. /package/{migrations → src/migrations}/950106_unique_settlement_model_ledger_account_currency.js +0 -0
  355. /package/{migrations → src/migrations}/950109_fxQuote.js +0 -0
  356. /package/{migrations → src/migrations}/950110_fxQuoteResponse.js +0 -0
  357. /package/{migrations → src/migrations}/950111_fxQuoteError.js +0 -0
  358. /package/{migrations → src/migrations}/950113_fxQuoteDuplicateCheck.js +0 -0
  359. /package/{migrations → src/migrations}/950114_fxQuoteResponseDuplicateCheck.js +0 -0
  360. /package/{migrations → src/migrations}/950115_fxQuoteConversionTerms.js +0 -0
  361. /package/{migrations → src/migrations}/950116_fxQuoteConversionTermsExtension.js +0 -0
  362. /package/{migrations → src/migrations}/950117_fxQuoteResponseConversionTerms.js +0 -0
  363. /package/{migrations → src/migrations}/950118_fxQuoteResponseConversionTermsExtension.js +0 -0
  364. /package/{migrations → src/migrations}/950119_fxCharge.js +0 -0
  365. /package/{migrations → src/migrations}/960111_alter_fxTransferParticipant__addFiled_externalParticipantId.js +0 -0
  366. /package/{migrations → src/migrations}/960112_fxTransfer-indexes2.js +0 -0
  367. /package/{migrations → src/migrations}/960113_fxTransferExtension-indexes.js +0 -0
  368. /package/{migrations → src/migrations}/960114_fxTransferTimeout-indexes2.js +0 -0
  369. /package/{migrations → src/migrations}/961000_participantEndpoint_unique.js +0 -0
  370. /package/{migrations → src/migrations}/migration.template +0 -0
  371. /package/{seeds → src/seeds}/amountType.js +0 -0
  372. /package/{seeds → src/seeds}/balanceOfPayments.js +0 -0
  373. /package/{seeds → src/seeds}/bulkProcessingState.js +0 -0
  374. /package/{seeds → src/seeds}/bulkTransferState.js +0 -0
  375. /package/{seeds → src/seeds}/currency.js +0 -0
  376. /package/{seeds → src/seeds}/endpointType.js +0 -0
  377. /package/{seeds → src/seeds}/fxParticipantCurrencyType.js +0 -0
  378. /package/{seeds → src/seeds}/fxTransferType.js +0 -0
  379. /package/{seeds → src/seeds}/ledgerAccountType.js +0 -0
  380. /package/{seeds → src/seeds}/ledgerEntryType.js +0 -0
  381. /package/{seeds → src/seeds}/participantLimitType.js +0 -0
  382. /package/{seeds → src/seeds}/partyIdentifierType.js +0 -0
  383. /package/{seeds → src/seeds}/partyType.js +0 -0
  384. /package/{seeds → src/seeds}/settlementDelay.js +0 -0
  385. /package/{seeds → src/seeds}/settlementGranularity.js +0 -0
  386. /package/{seeds → src/seeds}/settlementState.js +0 -0
  387. /package/{seeds → src/seeds}/settlementWindow1State.js +0 -0
  388. /package/{seeds → src/seeds}/settlementWindow2Open.js +0 -0
  389. /package/{seeds → src/seeds}/transactionInitiator.js +0 -0
  390. /package/{seeds → src/seeds}/transactionInitiatorType.js +0 -0
  391. /package/{seeds → src/seeds}/transactionScenario.js +0 -0
  392. /package/{seeds → src/seeds}/transferParticipantRoleType.js +0 -0
  393. /package/{seeds → src/seeds}/transferState.js +0 -0
  394. /package/{seeds → src/seeds}/z1000_settlementModel-deprecated.js- +0 -0
@@ -62,8 +62,6 @@ const ActionNotSupportedText = 'The action is not supported'
62
62
  const ParticipantAccountCurrencyMismatchText = 'The account does not match participant or currency specified'
63
63
  const ParticipantAccountMismatchText = 'Participant/account mismatch'
64
64
  const ParticipantInactiveText = 'Participant is currently set inactive'
65
- const ParticipantInitialPositionExistsText = 'Participant Limit or Initial Position already set'
66
- // const ParticipantNotFoundText = 'Participant does not exist'
67
65
 
68
66
  const create = async (payload) => {
69
67
  const log = logger.child({ payload })
@@ -213,7 +211,7 @@ const addEndpoint = async (name, payload) => {
213
211
  log.verbose('getting participant by name...')
214
212
  const participant = await ParticipantModel.getByName(name)
215
213
  participantExists(participant)
216
- log.info('adding endpoint for participant', { participant })
214
+ log.debug('adding endpoint for participant', { participant })
217
215
  return ParticipantFacade.addEndpoint(participant.participantId, payload)
218
216
  } catch (err) {
219
217
  log.error('error adding endpoint', err)
@@ -339,8 +337,9 @@ const addLimitAndInitialPosition = async (participantName, limitAndInitialPositi
339
337
  const existingPosition = await ParticipantPositionModel.getByParticipantCurrencyId(participant.participantCurrencyId)
340
338
  const existingSettlementPosition = await ParticipantPositionModel.getByParticipantCurrencyId(settlementAccount.participantCurrencyId)
341
339
  if (existingLimit || existingPosition || existingSettlementPosition) {
342
- log.warn('participant limit or initial position already set')
343
- throw ErrorHandler.Factory.createInternalServerFSPIOPError(ParticipantInitialPositionExistsText)
340
+ const errorMessage = `Participant Limit or Initial Position already set for participant: ${participantName}.`
341
+ log.warn(errorMessage)
342
+ throw ErrorHandler.Factory.createInternalServerFSPIOPError(errorMessage)
344
343
  }
345
344
  const limitAndInitialPosition = Object.assign({}, limitAndInitialPositionObj, { name: participantName })
346
345
  if (!limitAndInitialPosition.initialPosition) {
@@ -284,7 +284,7 @@ const processFxPositionPrepareBin = async (
284
284
 
285
285
  resultMessages.push({ binItem, message: Utility.clone(resultMessage) })
286
286
 
287
- if (changePositions) {
287
+ if (changePositions && participantLimit.thresholdAlarmPercentage) {
288
288
  Logger.isDebugEnabled && Logger.debug(`processFxPositionPrepareBin::limitAlarm: ${currentPosition.toNumber()} > ${liquidityCover.multiply(participantLimit.thresholdAlarmPercentage)}`)
289
289
  if (currentPosition.toNumber() > liquidityCover.multiply(participantLimit.thresholdAlarmPercentage).toNumber()) {
290
290
  limitAlarms.push(participantLimit)
@@ -39,6 +39,7 @@ const Config = require('../../lib/config')
39
39
  const Utility = require('@mojaloop/central-services-shared').Util
40
40
  const MLNumber = require('@mojaloop/ml-number')
41
41
  const Logger = require('../../shared/logger').logger
42
+ const assert = require('node:assert')
42
43
 
43
44
  /**
44
45
  * @function processPositionFxTimeoutReservedBin
@@ -89,6 +90,9 @@ const processPositionFxTimeoutReservedBin = async (
89
90
  Logger.isDebugEnabled && Logger.debug(`accumulatedFxTransferStates: ${JSON.stringify(accumulatedFxTransferStates)}`)
90
91
 
91
92
  const transferAmount = fetchedReservedPositionChangesByCommitRequestIds[commitRequestId][participantAccountId].change
93
+ if (transferAmount === undefined) {
94
+ throw new Error(`transferAmount is undefined for commitRequestId: ${commitRequestId} and ${participantAccountId}`)
95
+ }
92
96
 
93
97
  // Construct payee notification message
94
98
  const resultMessage = _constructFxTimeoutReservedResultMessage(
@@ -167,6 +171,8 @@ const _constructFxTimeoutReservedResultMessage = (binItem, commitRequestId, coun
167
171
  }
168
172
 
169
173
  const _handleParticipantPositionChange = (runningPosition, transferAmount, commitRequestId, accumulatedPositionReservedValue) => {
174
+ assert(runningPosition !== undefined)
175
+ assert(transferAmount !== undefined)
170
176
  const transferStateId = Enum.Transfers.TransferInternalState.EXPIRED_RESERVED
171
177
  // Revert payer's position for the amount of the transfer
172
178
  const updatedRunningPosition = new MLNumber(runningPosition.subtract(transferAmount).toFixed(Config.AMOUNT.SCALE))
@@ -285,7 +285,7 @@ const processPositionPrepareBin = async (
285
285
 
286
286
  resultMessages.push({ binItem, message: Utility.clone(resultMessage) })
287
287
 
288
- if (changePositions) {
288
+ if (changePositions && participantLimit.thresholdAlarmPercentage) {
289
289
  Logger.isDebugEnabled && Logger.debug(`processPositionPrepareBin::limitAlarm: ${currentPosition.toNumber()} > ${liquidityCover.multiply(participantLimit.thresholdAlarmPercentage)}`)
290
290
  if (currentPosition.toNumber() > liquidityCover.multiply(participantLimit.thresholdAlarmPercentage).toNumber()) {
291
291
  limitAlarms.push(participantLimit)
@@ -191,7 +191,7 @@ const registerTransferHandler = async () => {
191
191
  * @async
192
192
  * @description Registers all handlers in transfers
193
193
  *
194
- * @returns {boolean} - Returns a boolean: true if successful, or throws and error if failed
194
+ * @returns Promise<boolean> - Returns a boolean: true if successful, or throws and error if failed
195
195
  */
196
196
  const registerAllHandlers = async () => {
197
197
  try {
@@ -62,6 +62,9 @@ Program.command('handler') // sub-command name, coffeeType = type, required
62
62
  .option('--bulkfulfil', 'Start the Bulk Fulfil Handler')
63
63
  .option('--bulkprocessing', 'Start the Bulk Processing Handler')
64
64
  .option('--bulkget', 'Start the Bulk Get Handler')
65
+ .option('--deferredSettlement', 'Start the Deferred Settlement Handler.')
66
+ .option('--grossSettlement', 'Start the Gross Settlement Handler.')
67
+ .option('--rules', 'Start the rules handler.')
65
68
  // .option('--reject', 'Start the Reject Handler')
66
69
 
67
70
  // function to execute when command is uses
@@ -156,6 +159,33 @@ Program.command('handler') // sub-command name, coffeeType = type, required
156
159
  handlerList.push(handler)
157
160
  }
158
161
 
162
+ if (args.deferredSettlement === true) {
163
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --deferredSettlement')
164
+ const handler = {
165
+ type: 'deferredSettlement',
166
+ enabled: true
167
+ }
168
+ handlerList.push(handler)
169
+ }
170
+
171
+ if (args.grossSettlement === true) {
172
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --grossSettlement')
173
+ const handler = {
174
+ type: 'grossSettlement',
175
+ enabled: true
176
+ }
177
+ handlerList.push(handler)
178
+ }
179
+
180
+ if (args.rules === true) {
181
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --rules')
182
+ const handler = {
183
+ type: 'rules',
184
+ enabled: true
185
+ }
186
+ handlerList.push(handler)
187
+ }
188
+
159
189
  module.exports = Setup.initialize({
160
190
  service: 'handler',
161
191
  port: Config.PORT,
@@ -276,8 +276,6 @@ const positions = async (error, messages) => {
276
276
  *
277
277
  * @async
278
278
  * @description Registers the handler for position topic. Gets Kafka config from default.json
279
- *
280
- * @returns {boolean} - Returns a boolean: true if successful, or throws and error if failed
281
279
  */
282
280
  const registerPositionHandler = async () => {
283
281
  try {
@@ -37,8 +37,9 @@ const EventSdk = require('@mojaloop/event-sdk')
37
37
  const BinProcessor = require('../../domain/position/binProcessor')
38
38
  const SettlementModelCached = require('../../models/settlement/settlementModelCached')
39
39
  const Utility = require('@mojaloop/central-services-shared').Util
40
- const Kafka = require('@mojaloop/central-services-shared').Util.Kafka
41
- const { Kafka: { otel }, Util: { Producer, Consumer } } = require('@mojaloop/central-services-stream')
40
+ const { Kafka } = Utility
41
+ const { Consumer, Producer } = require('@mojaloop/central-services-stream').Util
42
+ const otel = require('@mojaloop/central-services-stream').Kafka.otel
42
43
  const Enum = require('@mojaloop/central-services-shared').Enum
43
44
  const Metrics = require('@mojaloop/central-services-metrics')
44
45
  const Config = require('../../lib/config')
@@ -47,7 +48,7 @@ const ErrorHandler = require('@mojaloop/central-services-error-handling')
47
48
  const BatchPositionModel = require('../../models/position/batch')
48
49
  const decodePayload = require('@mojaloop/central-services-shared').Util.StreamingProtocol.decodePayload
49
50
  const { BATCHING } = require('../../shared/constants')
50
-
51
+ const Logger = require('../../shared/logger').logger
51
52
  const consumerCommit = true
52
53
  const rethrow = require('../../shared/rethrow')
53
54
 
@@ -191,6 +192,7 @@ const positions = batchConfig => async (error, messages) => {
191
192
  }
192
193
  histTimerEnd({ success: true })
193
194
  } catch (err) {
195
+ Logger.error(`handlerBatch failed with error: ${err.message}`)
194
196
  // If Bin Processor returns failure
195
197
  // - Rollback DB transaction
196
198
  await trx?.rollback()
@@ -220,8 +222,6 @@ const positions = batchConfig => async (error, messages) => {
220
222
  *
221
223
  * @async
222
224
  * @description Registers the handler for position topic. Gets Kafka config from default.json
223
- *
224
- * @returns {boolean} - Returns a boolean: true if successful, or throws and error if failed
225
225
  */
226
226
  const registerPositionHandler = async () => {
227
227
  try {
@@ -41,13 +41,11 @@
41
41
  * @function RegisterAllHandlers
42
42
  *
43
43
  * @async
44
- * @description Registers all handlers by using the require-glob to retrieve all handler exports in sub directories and access the registerAllHandlers()
45
- * in each of them. Every handler in the sub-folders must have a registerAllHandlers() function
46
- * @returns {boolean} - Returns a boolean: true if successful, or throws and error if failed
44
+ * @description Registers all handlers in ./handlers and ../settlement/handlers.
45
+ * @returns {boolean} - Returns a boolean: true if successful, or throws and error if failed.
47
46
  */
48
47
 
49
48
  const Logger = require('../shared/logger').logger
50
- const requireGlob = require('require-glob')
51
49
  const TransferHandlers = require('./transfers/handler')
52
50
  const PositionHandlers = require('./positions/handler')
53
51
  const PositionHandlersBatch = require('./positions/handlerBatch')
@@ -55,32 +53,11 @@ const TimeoutHandlers = require('./timeouts/handler')
55
53
  const AdminHandlers = require('./admin/handler')
56
54
  const BulkHandlers = require('./bulk')
57
55
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
56
+ const DeferredSettlementHandler = require('../settlement/handlers/deferredSettlement/handler')
57
+ const GrossSettlementHandler = require('../settlement/handlers/grossSettlement/handler')
58
+ const RulesHandler = require('../settlement/handlers/rules/handler')
58
59
 
59
- const registerAllHandlers = async () => {
60
- try {
61
- const modules = await requireGlob(['./**/handler.js'])
62
- for (const key in modules) {
63
- Logger.isInfoEnabled && Logger.info(`Registering handler module[${key}]: ${JSON.stringify(modules[key])}`)
64
- if (Object.prototype.hasOwnProperty.call(modules[key], 'handler')) {
65
- const handlerObject = modules[key]
66
- await handlerObject.handler.registerAllHandlers()
67
- } else {
68
- for (const subKey in modules[key]) {
69
- const handlerObject = modules[key][subKey]
70
- Logger.isInfoEnabled && Logger.info(` ⌙ Registering sub-handler module[${key}-${subKey}]: ${JSON.stringify(handlerObject)}`)
71
- await handlerObject.handler.registerAllHandlers()
72
- }
73
- }
74
- }
75
- return true
76
- } catch (err) {
77
- Logger.isErrorEnabled && Logger.error(err)
78
- throw ErrorHandler.Factory.reformatFSPIOPError(err)
79
- }
80
- }
81
-
82
- module.exports = {
83
- registerAllHandlers,
60
+ const handlers = {
84
61
  transfers: {
85
62
  registerAllHandlers: TransferHandlers.registerAllHandlers,
86
63
  registerPrepareHandler: TransferHandlers.registerPrepareHandler,
@@ -104,9 +81,47 @@ module.exports = {
104
81
  registerAdminHandlers: AdminHandlers.registerAllHandlers
105
82
  },
106
83
  bulk: {
84
+ registerAllHandlers: BulkHandlers.registerAllHandlers,
107
85
  registerBulkPrepareHandler: BulkHandlers.registerBulkPrepareHandler,
108
86
  registerBulkFulfilHandler: BulkHandlers.registerBulkFulfilHandler,
109
87
  registerBulkProcessingHandler: BulkHandlers.registerBulkProcessingHandler,
110
88
  registerBulkGetHandler: BulkHandlers.registerGetBulkTransferHandler
89
+ },
90
+ deferredSettlement: {
91
+ registerAllHandlers: DeferredSettlementHandler.registerAllHandlers,
92
+ registerSettlementWindowHandler: DeferredSettlementHandler.registerSettlementWindowHandler
93
+ },
94
+ grossSettlement: {
95
+ registerAllHandlers: GrossSettlementHandler.registerAllHandlers,
96
+ registerTransferSettlementHandler: GrossSettlementHandler.registerTransferSettlement,
97
+ registerRulesHandler: RulesHandler.registerRules
98
+ },
99
+ rules: {
100
+ registerAllHandlers: RulesHandler.registerAllHandlers,
101
+ registerRulesHandler: RulesHandler.registerRules
111
102
  }
112
103
  }
104
+
105
+ const registerAllHandlers = async () => {
106
+ try {
107
+ Logger.isInfoEnabled && Logger.info('registerAllHandlers() - Registering all handlers.')
108
+ await handlers.transfers.registerAllHandlers()
109
+ await handlers.positions.registerAllHandlers()
110
+ await handlers.timeouts.registerAllHandlers()
111
+ await handlers.admin.registerAdminHandlers()
112
+ await handlers.bulk.registerAllHandlers()
113
+ await handlers.deferredSettlement.registerAllHandlers()
114
+ await handlers.grossSettlement.registerAllHandlers()
115
+ await handlers.rules.registerAllHandlers()
116
+
117
+ return true
118
+ } catch (err) {
119
+ Logger.isErrorEnabled && Logger.error(err)
120
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
121
+ }
122
+ }
123
+
124
+ module.exports = {
125
+ registerAllHandlers,
126
+ ...handlers
127
+ }
@@ -292,7 +292,6 @@ const _processFxForwardedTransfers = async (fxTransferForwardedList) => {
292
292
  * Processes timedOut fxTransfers
293
293
  *
294
294
  * @param {TimedOutFxTransfer[]} fxTransferTimeoutList
295
- * @returns {Promise<void>}
296
295
  */
297
296
  const _processFxTimedOutTransfers = async (fxTransferTimeoutList) => {
298
297
  const fspiopError = createFSPIOPTimeoutError()
@@ -380,8 +379,6 @@ const _processFxTimedOutTransfers = async (fxTransferTimeoutList) => {
380
379
  * ... called to validate/insert ...
381
380
  *
382
381
  * @param {error} error - error thrown if something fails within Cron
383
- *
384
- * @returns {boolean} - Returns a boolean: true if successful, or throws and error if failed
385
382
  */
386
383
  const timeout = async () => {
387
384
  if (running) return
@@ -544,7 +541,7 @@ const initializeMetrics = () => {
544
541
  *
545
542
  * @async
546
543
  * @description Registers the timeout handler by starting the timeoutJob cron
547
- * @returns {boolean} - Returns a boolean: true if successful, or throws and error if failed
544
+ * @returns {Promise<boolean>} - Returns a boolean: true if successful, or throws and error if failed
548
545
  */
549
546
  const registerTimeoutHandler = async () => {
550
547
  try {
@@ -0,0 +1,209 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2026 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * TigerBeetle
23
+ - Lewis Daly <lewis@tigerbeetle.com>
24
+ --------------
25
+ ******/
26
+
27
+ import { after, before, describe, it } from "node:test"
28
+ import Harness from '../../testing/harness'
29
+ import * as ApiHelpers from '../../testing/api-helpers'
30
+ import assert from "node:assert"
31
+ import { assertPositionDiff } from "../../testing/util"
32
+
33
+ const harness = Harness.getInstance()
34
+ let PrepareHandler: any
35
+ let TransferHandler: any
36
+ let PositionBatchHandler: any
37
+ let ExternalParticipantCached: any
38
+ let TransferFacade: any
39
+ let FxTransferService: any
40
+ let proxyCache: any
41
+
42
+ describe('handlers/fx-abort', () => {
43
+ before(async () => {
44
+ await harness.up('BATCH')
45
+ await harness.setupGlobals()
46
+
47
+ // Import after bringing up the harness, so that global config is overriden.
48
+ TransferHandler = require('./handler')
49
+ PrepareHandler = require('./prepare')
50
+ PositionBatchHandler = require('../positions/handlerBatch')
51
+ TransferFacade = require('../../models/transfer/facade')
52
+ FxTransferService = require('../../domain/fx/index')
53
+ ExternalParticipantCached = require('../../models/participant/externalParticipantCached')
54
+ proxyCache = require('../../lib/proxyCache')
55
+ await proxyCache.connect()
56
+ await TransferHandler.registerPrepareHandler()
57
+ await TransferHandler.registerFulfilHandler()
58
+
59
+ // Create the hub accounts + settlement model.
60
+ const createHubPayload: ApiHelpers.CreateHubPayload = {
61
+ currencies: ['BWP', 'USD'],
62
+ settlementModels: [
63
+ {
64
+ name: `DEFERRED_MULTILATERAL_NET_BWP`,
65
+ settlementGranularity: "NET",
66
+ settlementInterchange: "MULTILATERAL",
67
+ settlementDelay: "DEFERRED",
68
+ currency: 'BWP',
69
+ requireLiquidityCheck: true,
70
+ ledgerAccountType: "POSITION",
71
+ settlementAccountType: "SETTLEMENT",
72
+ autoPositionReset: true
73
+ },
74
+ {
75
+ name: `DEFERRED_MULTILATERAL_NET_USD`,
76
+ settlementGranularity: "NET",
77
+ settlementInterchange: "MULTILATERAL",
78
+ settlementDelay: "DEFERRED",
79
+ currency: 'USD',
80
+ requireLiquidityCheck: true,
81
+ ledgerAccountType: "POSITION",
82
+ settlementAccountType: "SETTLEMENT",
83
+ autoPositionReset: true
84
+ }
85
+ ]
86
+ }
87
+ await ApiHelpers.createHub(harness, createHubPayload)
88
+ // Create 2 test dfsps to transfer between.
89
+ await ApiHelpers.createDfsp(harness, {
90
+ name: 'dfsp_a',
91
+ currencies: ['BWP'],
92
+ isProxy: false,
93
+ initialPostionsAndLimits: [{ initialPosition: 0, value: 100000 }],
94
+ deposits: [10000]
95
+ })
96
+ await ApiHelpers.createDfsp(harness, {
97
+ name: 'dfsp_b',
98
+ currencies: ['BWP', 'USD'],
99
+ isProxy: false,
100
+ initialPostionsAndLimits: [
101
+ { initialPosition: 0, value: 100000 },
102
+ { initialPosition: 0, value: 100000 }
103
+ ],
104
+ deposits: [10000, 10000]
105
+ })
106
+ await ApiHelpers.createDfsp(harness, {
107
+ name: 'dfsp_a_proxy',
108
+ currencies: ['BWP', 'USD'],
109
+ isProxy: true,
110
+ initialPostionsAndLimits: [
111
+ { initialPosition: 0, value: 100000 },
112
+ { initialPosition: 0, value: 100000 }
113
+ ],
114
+ deposits: [10000, 10000]
115
+ })
116
+ await ApiHelpers.createDfsp(harness, {
117
+ name: 'dfsp_b_proxy',
118
+ currencies: ['BWP', 'USD'],
119
+ isProxy: true,
120
+ initialPostionsAndLimits: [
121
+ { initialPosition: 0, value: 100000 },
122
+ { initialPosition: 0, value: 100000 }
123
+ ],
124
+ deposits: [10000, 10000]
125
+ })
126
+ await ApiHelpers.createDfsp(harness, {
127
+ name: 'fxp_a',
128
+ currencies: ['BWP', 'USD'],
129
+ isProxy: false,
130
+ initialPostionsAndLimits: [
131
+ { initialPosition: 0, value: 100000 },
132
+ { initialPosition: 0, value: 100000 }
133
+ ],
134
+ deposits: [10000, 10000]
135
+ })
136
+
137
+ // Set up the proxy1 currencies.
138
+ await proxyCache.getCache().addDfspIdToProxyMapping('external_dfsp_a', 'dfsp_a_proxy')
139
+ await proxyCache.getCache().addDfspIdToProxyMapping('external_dfsp_b', 'dfsp_b_proxy')
140
+
141
+ // Create payment of $100.00 USD from dfsp_a to dfsp_b with id 1000001.
142
+ await ApiHelpers.buildPayment()
143
+ .deps(harness, TransferHandler)
144
+ .parties('dfsp_a', 'dfsp_b')
145
+ .transferId('1000001')
146
+ .amount('1.00', 'BWP')
147
+ .build()
148
+ .prepareAndFulfil()
149
+ })
150
+
151
+ after(async () => {
152
+ await proxyCache.disconnect()
153
+ await harness.teardownGlobals()
154
+ await harness.down()
155
+ })
156
+
157
+ it('Aborting a transfer also aborts linked fxTransfer, all positions revert.', async () => {
158
+ const positionPayerPre = await ApiHelpers.getPositionAccount('dfsp_a', 'BWP')
159
+ const positionFxpBwpPre = await ApiHelpers.getPositionAccount('fxp_a', 'BWP')
160
+ const positionFxpUsdPre = await ApiHelpers.getPositionAccount('fxp_a', 'USD')
161
+ const positionPayeePre = await ApiHelpers.getPositionAccount('dfsp_b', 'USD')
162
+
163
+ const forex = ApiHelpers.buildForex()
164
+ .deps(harness, TransferHandler)
165
+ .commitRequestId('5000001')
166
+ .determiningTransferId('6000001')
167
+ .parties('dfsp_a', 'fxp_a')
168
+ .amountSource('100.00', 'BWP')
169
+ .amountTarget('10.00', 'USD')
170
+ .build()
171
+
172
+ await forex.prepare()
173
+ const positionPayerPostPrepare = await ApiHelpers.getPositionAccount('dfsp_a', 'BWP')
174
+ assertPositionDiff('payer', positionPayerPre, positionPayerPostPrepare, { posted: 100 })
175
+
176
+ await forex.fulfil()
177
+ const fxTransferAfterFulfil = await FxTransferService.getByIdLight('5000001')
178
+ assert.equal(fxTransferAfterFulfil.fxTransferState, 'RECEIVED_FULFIL_DEPENDENT')
179
+
180
+ const payment = ApiHelpers.buildPayment()
181
+ .deps(harness, TransferHandler)
182
+ .parties('fxp_a', 'dfsp_b')
183
+ .transferId('6000001')
184
+ .amount('10.00', 'USD')
185
+ .fx()
186
+ .build()
187
+
188
+ await payment.prepare()
189
+ // Need to do a custom fulfil here, as we expect 4 messages due to FX.
190
+ const mark = harness.redpandaMark()
191
+ await TransferHandler.fulfil(null, payment.buildMessageAbort())
192
+ await harness.redpandaDrain(mark, 4)
193
+
194
+ const transfer = await TransferFacade.getById('6000001')
195
+ assert.equal(transfer.transferState, 'ABORTED_ERROR')
196
+ const fxTransferAfterAbort = await FxTransferService.getByIdLight('5000001')
197
+ assert.equal(fxTransferAfterAbort.fxTransferState, 'ABORTED_ERROR')
198
+
199
+ // All positions reset.
200
+ const positionPayerPostAbort = await ApiHelpers.getPositionAccount('dfsp_a', 'BWP')
201
+ assertPositionDiff('payer', positionPayerPre, positionPayerPostAbort, { posted: 0 })
202
+ const positionFxpUsdPostAbort = await ApiHelpers.getPositionAccount('fxp_a', 'USD')
203
+ assertPositionDiff('payer', positionFxpUsdPre, positionFxpUsdPostAbort, { posted: 0 })
204
+ const positionPayeePostAbort = await ApiHelpers.getPositionAccount('dfsp_b', 'USD')
205
+ assertPositionDiff('payee', positionPayeePre, positionPayeePostAbort, { posted: 0 })
206
+ const positionFxpBwpPostAbort = await ApiHelpers.getPositionAccount('fxp_a', 'BWP')
207
+ assertPositionDiff('payer', positionFxpBwpPre, positionFxpBwpPostAbort, { posted: 0 })
208
+ })
209
+ })