mojaloop / mojaloop-specification

This repo contains the specification document set of the Open API for FSP Interoperability
https://docs.mojaloop.io/api
Other
20 stars 40 forks source link

Change Request: Currency conversion support in Mojaloop #89

Open mjbrichards opened 3 years ago

mjbrichards commented 3 years ago

Open API for FSP Interoperability - Change Request

Table of Contents

1. Preface


This section contains basic information regarding the change request.

1.1 Change Request Information

Requested By Michael Richards, ModusBox
Change Request Status In review ☒ / Approved ☐ / Rejected ☐
Approved/Rejected Date

1.2 Document Version Information

Version Date Author Change Description
1.0 2021-06-15 Michael Richards Initial statement.

2. Problem Description


2.1 Background

There has been discussion for some time in the Mojaloop community about how to manage currency conversion as part of funds transfers. A version of this has been implemented by Mowali, but this has operational drawbacks which have prompted a search for a simpler and more robust alternative. Following discussions with interested parties, an initial statement of a proposed solution has been created and is attached to this document.

This solution (like any solution to the problem of currency conversion) will require some changes to the FSPIOP API, and these are described in Section 6.1 of the attached document. It is proposed that the required changes should be non-breaking, but this is a matter for review.

2.2 Current Behaviour

The API does not support currency conversion at present.

Explain how you would like the API to behave.

The attached document explains the proposed behaviour

3. Proposed Solution Options


API Candidate for currency conversion support in Mojaloop.docx

MichaelJBRichards commented 1 year ago

With apologies for the delay, I attach a revised sequence diagram and API definition document which are intended to address the problem of privacy relating to currency conversion information, while still allowing the transfer information to contain sufficient information to allow the switch to record the correct obligations. The base idea is that the debtor and creditor FSPs maintain an optional list of one or more dependents. Each dependent is the creditor party in a part of the transfer, which will have been committed before the transfer as a whole is committed, but whose obligations are not finally recorded by the switch until the main transfer has completed. The dependent contains the condition and fulfilment which refer to the subsidiary task, and sufficient information to allow the switch correctly to record the obligations associated with all the subsidiary tasks as well as the main task itself.

API Candidate for currency conversion support in Mojaloop v2.3.docx

FXNext Version 2 - Payer conversion

henrka commented 1 year ago

Thanks @MichaelJBRichards,

Comments including some follow up on earlier discussions, sorry if I'm repeating myself:

By removing these two, you would remove potential business sensitive information containing the FX rate from the Payer FSP to the Payee FSP, while still allowing the message to be signed.

MichaelJBRichards commented 1 year ago

But surely both parties will always know the exchange rate, because the quote response contains both the send amount and the payee receive amount? And the sending customer needs to know both.

I still think that the currency conversion, whichever party executed it (and both might), needs to form part of the terms on which the payment was agreed; not least because one of our RESTful principles is that a message should contain all of the information which the recipient needs to act on it. This means, I think that the PUT /transfers message needs to contain all of the information that the switch will need to assign the values correctly to its ledgers. You will note that I have restricted the definition of a dependent to include only the participant and the amount; but these are, I think, necessary for the switch to be able correctly to distribute the obligations incurred as a consequence of the payment. So the payee institution will definitely need to know which FXP performed the conversion; and, since this is the case, I saw no good reason not to include the information in the terms of the payment.

henrka commented 1 year ago

But surely both parties will always know the exchange rate, because the quote response contains both the send amount and the payee receive amount? And the sending customer needs to know both.

No, the quote callback only contains the amounts in the Payee's currency (see note between Step 34 and 35 in your flow, where all amounts are in RWF). The Payer FSP already knows the currency conversion required from the POST /fxQuotes and its callback (see Steps 20 to 28), and can as such show the amounts in both currencies to the Payer in Step 39. The Payer FSP will then use POST /fxTransfers to perform the required conversion (see note between step 42 and 43). This way there is no need for the Payee FSP to know anything about if or how a currency conversion has been performed, perhaps the Payer FSP had an account in both currencies that could be used for the transfer.

I still think that the currency conversion, whichever party executed it (and both might), needs to form part of the terms on which the payment was agreed; not least because one of our RESTful principles is that a message should contain all of the information which the recipient needs to act on it.

We are not sending all information in all requests today. For example in the POST /transfers, we are relying on information that has earlier been agreed in the POST /quotes. We are not stating that we are fully RESTful compliant. Why is it necessary for the Payee FSP in the flow above to know that a currency conversion has been performed, as long as it receives the required funds in the correct currency in some way from the Payer FSP? Maybe there is some very important reason, but then I would like to understand it.

You will note that I have restricted the definition of a dependent to include only the participant and the amount; but these are, I think, necessary for the switch to be able correctly to distribute the obligations incurred as a consequence of the payment.

The Switch has already reserved the transfers related to the currency conversion in earlier steps (POST /fxTransfers and its related callback, Steps 42 to 53), now it just needs to commit what has earlier been reserved? Sending the same thing again in POST /transfers as in POST /fxTransfers would just introduce potential errors in my view. Minimizing the information in POST /transfers would also minimize the changes needed for existing implementers.

So the payee institution will definitely need to know which FXP performed the conversion; and, since this is the case, I saw no good reason not to include the information in the terms of the payment.

Is this necessary per transfer in the Payee FSP? What I as a Payee FSP is interested in per transfer is that I have received the funds from the Payer FSP in my account at the Switch in some way so that I can be assured that I can perform the transfer to my account holder. As a Payee FSP I don't really care about the internal accounting in the Switch, i.e. if there were some other participant in between, such as the FXP, that actually sent the funds to me. In the Switch it is vital information to keep track of the internal accounting. But in the integration between the Payer FSP and Payee FSP, I don't see it as required information. But maybe there are other principles in Mojaloop that requires this?

PaulGregoryBaker commented 1 year ago

I like the fx flow above. Doing the POST \fxQuote before the POST \transfers only works for the transfer amount type 'RECEIVE'. To support receive transfer type presumably the POST \quotes would have to be called before the POST \fxQuote. Maybe we should build another sequence diagram for that.

MichaelJBRichards commented 1 year ago

Thanks for your comments, @PaulGregoryBaker. I'm afraid we shan't be able to call quotes before we call fxQuotes, since the condition returned by fxQuotes forms part of the terms of the payment. Since this is the case, generation of a new condition in the process of re-quoting for currency conversion would invalidate the condition in the quote response for the transfer. In the case where the amountType was RECEIVE and the creditor party added fees, the debtor party would have to go round another quotation and approval cycle including the new conversion.

I've done some further thinking around the points raised by @henrka. Essentially, I think that reducing the information in the message to preserve the privacy of the conversion, as @henrka rightly proposes, implies further effort on the part of the switch. In previous incarnations, the burden on the switch (and especially the code changes required) were relatively light. I think that they are now more extensive, so I've included a separate document where I set out what I think they might be.

I've also revised the sequence diagram, and have aligned it with the latest state of the API document - in our various modifications it had got somewhat our of kilter. I attach all three documents, and await your comments with interest.

Converting dependencies to obligations.docx API Candidate for currency conversion support in Mojaloop v2.4.docx FXNext Version 2 4 - Payer conversion

PaulGregoryBaker commented 1 year ago

Nice. There is a small error in the text description on 39.

MichaelJBRichards commented 1 year ago

FXNext Version 2 4 - Payee conversion

A version of the sequence diagram showing currency conversion being initiated by the creditor participant.

henrka commented 1 year ago

Thanks @MichaelJBRichards,

Please find my initial comments/questions on the new flow where the Payee FSP performs the currency conversion:

MichaelJBRichards commented 1 year ago

Thank you, @henrka , for your usual careful review. I have been doing some refactoring in order to align the FX API more closely with the way in which I would expect the ISO 20022 version of the FX API to work, and I will describe that later; but I will start, as usual, by commenting on your comments:

When I started thinking about how we might represent currency conversions in ISO 20022, it seemed to me that we wanted to make the content of the currency conversion endpoints as close as we could to the ordinary payment endpoints. So a currency conversion execution would be strongly analogous to an ordinary payment execution. The main obstacle to this seemed to me to be the dependents structure. I therefore propose that we should replace the dependents structure, in which the payment contains all the information about the subordinates (such as the conversion), with an additional field in the subordinate which links it to the master payment, using the master payment's transaction ID. This would, I think, achieve the same effect but with greater simplicity for the data structures (and it removes your reservation about using the condition...) I have produced a new version of the draft API specification incorporating this idea, and attach it, together with a new sequence diagram which shows the flow for a payment where conversion is done by the payee, but the amount is a RECEIVE amount (i.e. something like a merchant payment.) Let me know what you think.

API Candidate for currency conversion support in Mojaloop v2.6.docx FXNext Version 2 6 - Payee conversion with RECEIVE amount

henrka commented 1 year ago

Thanks @MichaelJBRichards,

The changed flow without dependents is better! Please find my comments as usual (now with numbers instead to make it easier to relate to which one it is):

  1. Step 8: As per our recent discussion in Slack to allow the Payee FSP to know the Payer's currency in case the Payee FSP should perform the currency conversion, it would make sense to change receiveCurrencies to supportedCurrencies, or just currencies instead. The currency information of the Payer would then be sent as part of the Party information in the POST /quotes in Step 13.
  2. Step 13: See above to include Upile's currency.
  3. Step 17: The currency that Upile is using would need to be known at this step (see comments above)
  4. Note between 25 and 26: The amountType is SEND here, I would believe that is a copy-paste error and it should be RECEIVE?
  5. Note between 25 and 26: Could we remove the conversion type, and have its parameters on the root level of POST /fxQuotes instead? The conversion type doesn't seem to be reused, so I don't know if there is a need to have a specific type for it? This would make the PUT /quotes more similar to data models for other requests in the FSPIOP API.
  6. Note between 25 and 26: Is there a need for both the conversionRequestId and conversionId? Neither seems to be reused outside of the scope of the POST/PUT /fxQuotes.
  7. Note between 29 and 30: I suspect you have read too many ISO specs now when you are abbreviating transaction in governingTx :). POST /fxTransfers seems to use relatedTransactionId, can we please change to that or governingTransaction or similar? Also related to governingTx, how does FDH FX know the transaction ID, it is not sent in the POST /fxQuotes?
  8. Note between 29 and 30: Could we remove the conversionTerms type, and have its parameters on the root level of PUT /fxQuotes instead? The conversionTerms type doesn't seem to be reused, so I don't know if there is a need to have a specific type for it? This would make the PUT /fxQuotes more similar to data models for other requests in the FSPIOP API.
  9. Step 34, The text "OK, so I will charge 2 ZMW for this" would be easier to follow if it said something like "OK, I will add 2 ZMW on top of the conversion fee".
  10. Note between 35 and 36: The Transaction type (at least in current version) doesn't contain a payeeReceiveAmount, is this something that should be added or is the payeeReceiveAmount in the PUT /quotes enough?
  11. Step 39: This should be 250 MWK instead of 5 ZMW.
  12. Step 40: Mulenga will receive 100 ZMW according to the payeeReceiveAmount.
  13. Note between 42 and 43: See earlier comment on payeeReceiveAmount in Transaction type.
  14. Note between 49 and 50: relatedTransactionId, is this same as the earlier governingTx? Can we stick to one?
  15. Note between 49 and 50: The key to perform the FX Quote, wouldn't it be more logical for the FXP to use the ID of the FX Quote instead of the ID of the transaction (relatedTransactionId)? For the Switch the transaction ID is probably more important, but for the FXP the FX Quote should be the important key, so for me it would be logical to include both.
  16. Step 52: "Does the sender have an account in this currency?" Which one of the currencies? :)
MichaelJBRichards commented 1 year ago

New version of the FX functionality, which now supports conversion via a reference currency. The basic thinking behind this is:

I attach the revised draft API and a sequence diagram illustrating this. Any comments you might have would be most welcome. API Candidate for currency conversion support in Mojaloop v2.7.docx FXNext Version 2 6 - Conversion via a reference currency with RECEIVE amount

MichaelJBRichards commented 1 year ago

My comments on your comments on the previous version of the sequence diagram:

I also made a couple of adjustments so that the creditor DFSP asks for its fee to be converted. This means that in the execution of the conversion the sums come out right...

In a belated attempt to make this issue easier for all of us, I have uploaded current versions of the documentation to our own repo in GitHub.

mdebarros commented 1 year ago

I attach the revised draft API and a sequence diagram illustrating this. Any comments you might have would be most welcome. API Candidate for currency conversion support in Mojaloop v2.7.docx FXNext Version 2 6 - Conversion via a reference currency with RECEIVE amount

Just some review comments:

  1. step 13, the POST /quotes has a typo suppoertedCurrencies -> suppoertedCurroencies
  2. step 62, this should go to the Payer FSP
  3. step 83, this should go to the Payer FSP
  4. step 84, this should go from Payer FSP back to the switch

@MichaelJBRichards FYI

henrka commented 1 year ago

My comments on your comments on the previous version of the sequence diagram:

  • 1, 2, 3, 4: fixed.
  • 5 and 8: I kind of like the idea of a conversion object, which I think of as containing the terms of the conversion in the same way as the transaction object contains the terms of the transfer. But I wouldn't die for it...
  • 6, 7, 9: fixed.
  • 10, 13: You are correct; I propose adding it to the transaction object in Section 7.1.3 of the API candidate.
  • 11, 12: fixed
  • 14: all instances now changed to determiningTransactionId
  • 15: I had thought to use the condition as the key for the FXP to recognise the terms it was being asked to execute: please execute the conversion for which these are the signed terms. But I'm open to persuasion.
  • 16: fixed

I also made a couple of adjustments so that the creditor DFSP asks for its fee to be converted. This means that in the execution of the conversion the sums come out right...

In a belated attempt to make this issue easier for all of us, I have uploaded current versions of the documentation to our own repo in GitHub.

Thanks @MichaelJBRichards,

Follow up on comments

Comments on the new flow in https://github.com/mojaloop/Currency-conversion/blob/main/FXNext%20Version%202.7%20-%20Payee%20conversion%20with%20RECEIVE%20amount.svg

  1. Note between step 46 and 47: How does the Switch here know that FDH_FX will be involved? Shouldn't it be NBS Bank (the Payer FSP) that the funds are reserved for? This seems to be corrected in note between 55 and 56, so probably just a typo..
  2. Step 62 and 65 both goes to Payee FSP. Shouldn't step 62 be a PATCH /fxTransfer with transferState=ABORTED to the FXP, to inform that the FX transfer was aborted due to the fulfillment mismatch?
  3. Step 72: NBS should probably be deactivated in the PlantUML code here...
  4. Step 76: Should we add Mulenga Kapwepwe as an actor that is actually receiving the 100 ZMW here, just for clarity?

Comments on the new flow in https://github.com/mojaloop/Currency-conversion/blob/main/FXNext%20Version%202.7%20-%20Payer%20conversion.svg

  1. Note between step 29 and 30: Following up on earlier discussions, I don't really understand why the Payer FSP should share their fees (the "charges") to do the FX conversion to the Payee FSP, this should be none of the Payee FSP business. The charges doesn't seem to be used by either the Switch or the Payee FSP. Shouldn't this instead contain a "converter": "PAYER" to inform that the Payer FSP has performed a currency conversion? This information is part of the PUT /quotes, so I guess this is just missed to be updated?
  2. Step 38: Currency should be MWK, not MWF.
  3. Step 52: If fulfillment doesn't match then the FXP should probably be informed of the same via a PATCH /fxTransfer with transferState=ABORTED.
  4. Note between 57 and 58: Should there be information in the POST /transfers that there is a dependent FX transfer, or will the Switch check in its database for each transfer if there is a dependent transfer?
  5. Step 65: Should we add Mulenga Kapwepwe as an actor that is actually receiving the 95 ZMW here, just for clarity?
MichaelJBRichards commented 1 year ago

Thanks very much for your comments, @henrka and @mdebarros .

On the sequence diagrams:

Conversion by the payee

  1. Editing failure. Fixed
  2. I think it should be added. Now have notification for both FXP and Payee DFSP.
  3. Done
  4. Good plan. Added her

Conversion by the payer

  1. Agree. Removed
  2. Done
  3. Again, added notification for FXP
  4. As you say, the intention is that the switch should check to see if there are any other transfers which depend on the transfer it is processing. I thought that this was a simpler way of structuring things.
  5. Added Mulengwa

Reference currency (per MdB)

  1. Fixed
  2. Fixed
  3. Fixed
  4. Fixed

I will upload new copies of the sequence diagrams to the repository, together with a copy of the new draft of the API and some further sequence diagrams.

mdebarros commented 1 year ago

Some issues with the markdown document (possible conversion issues?):

  1. See points 3,4 & 7 on Assumptions: https://github.com/mojaloop/Currency-conversion/blob/main/APICandidate%20for%20currency%20conversion%20support%20in%20Mojaloop.md#assumptions
  2. See the dangling empty point structure above the Functions of an FXP title: https://github.com/mojaloop/Currency-conversion/blob/main/APICandidate%20for%20currency%20conversion%20support%20in%20Mojaloop.md#functions-of-an-fxp
PaulGregoryBaker commented 1 year ago

I had a closer look at the optional converter field, and realised that it was no required for the reference currency flow that I was concerned about. I no longer have any concerns.

mdebarros commented 1 year ago

Also, just adding a comment from todays CCB discussion:

Raised issue on the implementation of the FX specification, specifically that Transfer prepare processing will ALWAYS have to check if there is an associated fxTransfers using the transactionId from the transaction-object.

As discussed this would be resolved in two ways:

  1. The transaction-object will include the converter fields - if they are available in the transaction-object, it will signify that there is an fxTransfer
  2. There is another proposal to include the transact-object as part of the transfers, so no additional look-ups would be required to attain the converter fields and the transactionId

@MichaelJBRichards please review the above comment, and let me know if we require any corrections.

MichaelJBRichards commented 1 year ago

I have uploaded a revised version of the candidate API document (MD version, natch) to the repository. It addresses comments made by Vijay in his review of the document.

millerabel commented 1 year ago

Hmm… one of the original design principles separates the transaction logic from the simple transfer of money. I’m reluctant to start down the slippery slope of consulting the transaction details from the transfer logic. Should it be possible to encode the currency and fx details that are relevant for transfer as instructions to the clearing engine (in the transfer object)? We should not pierce the veil of the transaction object from within the clearing engine.

mjbrichards commented 1 year ago

In this case there are two (or possibly even three) transaction objects. Well, one (or possibly two) of those are Conversion objects, which are the FX version of a transaction object. The set of objects are available to the switch in the same way as the transaction object is; and the switch checks that all the objects have been received and the associated requests approved before it finalises the payment and records all the obligations. So I don't think that there is a requirement to pierce the veil of the transaction object: it's just that this is a dance of the two (or possibly three) veils.

millerabel commented 1 year ago

The concept of a Transfer Set seems natural and obvious to me. If the set of related transfers (including the conversions and local transfers) are organized into a set object with deterministic processing rules we build on the Interledger guarantees. That suggests all-or-none, two-phase clearing and commit across the set, but should not necessarily require ordering of transfers.

mjbrichards commented 1 year ago

And I am happy to report that I think that's just what our proposed switch processing does. I would look forward to explaining how at the convening, but Cici wants to go big on cross-scheme currency conversion scenarios (and I, of course, concur). However, I am available to give, for a small fee, my famed explanation in which transfers are semi-convincingly played by beer bottles.

millerabel commented 1 year ago

I am all for prototypes using read-at-hand materials, especially when beer is involved.