stellar / stellar-protocol

Developer discussion about possible changes to the protocol.
517 stars 303 forks source link

SEP-6: fees for transactions using SEP-38 quotes #1061

Closed JakeUrban closed 2 years ago

JakeUrban commented 2 years ago

Problem Description

SEP-6's GET /fee endpoint states the following:

When using the /deposit-exchange or /withdraw-exchange endpoints fees are included in the conversion price provided with SEP-38 GET /price or SEP-38 POST /quote.

However, SEP-6's GET /transaction(s) endpoints include the amount_fee and optional amount_fee_asset attributes, implying that fixed fees can in fact be charged in addition to any margin included in the exchange rate between the assets used in the transaction.

Possible Solutions

There are two ways we can resolve this contradiction in our protocol, each with their pros and cons.

Solution 1: Remove amount_fee_asset from GET /transactions(s)

This is the simplest solution, although it technically is a breaking change. The statement made in the GET /fee endpoint description would remain as-is and the information contradicting that statement would be removed.

However, I don't think this is the right approach. Businesses should be able to decide how to charge fees for their services, and requiring a subset of transactions they facilitate to use a different fee mechanism imposes unnecessary restrictions for the sake of avoiding a protocol adjustment.

For example, lets say a cryptocurrency exchange charges flat and/or percentage fees for buying XLM with fiat USD as well as selling XLM for USD. Now lets say that exchange wants to make their services interoperable with the various Stellar ecosystem wallets applications. SEP-6 doesn't support fixed or percentage fees for transactions involving different assets, so the exchange is either out of luck or has to adjust their fee mechanisms for Stellar.

Solution 2: Support fees for transactions using quotes

This solution allows businesses to charge fees in any manner they choose. However, our GET /fee endpoint, and the fee-related info in GET /info endpoint, currently assumes fees are charged in units of the Stellar asset. There are a few ways we can resolve this.

Option 1: Adjust the request and response attributes to GET /fee (and GET /info)

This is difficult to design. My first thought was we could do something like the following examples.


GET /fee?asset_code=USDC&offchain_asset=iso4217:BRL&operation=deposit&amount=100&amount_asset=iso4217:BRL

{
    "fee": "2.00",
    "fee_asset": "stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
}

The request above means: I want to deposit 100 BRL for some unknown amount of USDC. The fee is 2 USDC.

GET /fee?asset_code=USDC&offchain_asset=iso4217:BRL&operation=withdrawal&amount=100&amount_asset=iso4217:BRL

{
    "fee": "5.00",
    "fee_asset": "iso4217:BRL"
}

The request above means: I want to withdraw some unknown amount of USDC and receive 100 BRL. The fee is 5 BRL.


This obviously is not ideal because the request info is incomplete: it doesn't provide the amount of the other asset. However adding a parameter for this would effectively allow the client to determine the exchange rate for a hypothetical transfer, which is nonsensical. Its also not clear if the anchor would even be able to give accurate fees without the amount of the other asset.

An adjustment could be to let the anchor decide the amount of the other asset and include it in the response. However, this requires indicative quote logic in the GET /fee endpoint, similar to SEP-38's GET /price(s). Do we really want to require anchors to do this?

Option 2: Deprecate the GET /fee endpoint

I'd like to go big here and question the real-world value of the GET /fee endpoint. The use case for it is as follows:

This endpoint is important to allow an anchor to accurately report fees to a user even when the fee schedule is complex. If a fee can be fully expressed with the fee_fixed and fee_percent fields in the /info response, then an anchor should not implement this endpoint.

What does it mean for a fee to be "complex"? It means there are many factors that go into its calculation. However, the GET /fee endpoint doesn't actually allow for many input factors. It has the following parameters:

The type parameter is really the key parameter here, however because the values are custom (i.e. defined in each anchor's GET /info endpoint) its effectively not interoperable and therefore not very useable.

Instead of continuing to try to standardize a method for calculating fees with complex structures, I vote to leave this feature behind and recognize that it does a poor job at what it aims to do.

leighmcculloch commented 2 years ago

Will Solution 2 Option 2, removing the endpoint, mean the client needs to first create the deposit/withdrawal to see the fees?

We probably still need some way to still communicate the fees earlier so that the user knows what the fees could be before they signup with an anchor. It could be as simple as raw text field that a wallet can choose to display or not. Max flex with min tech debt. Wdyt?

I'm also in favor of Solution 2 Option 2, removing the endpoint or replacing with idea above. It's clearly limited as it is and business should be able to innovate on fees. If we remove it, I think we can remove it gracefully by saying that clients shouldn't error if they get a 404 accessing it, and if it is not available, clients should rely on the fees defined in the deposit/withdraw response. If we replace with a raw text field we can add the text field as new and optional but recommended, deprecate old field.

JakeUrban commented 2 years ago

Will Solution 2 Option 2, removing the endpoint, mean the client needs to first create the deposit/withdrawal to see the fees?

Yes. Fees calculations cannot happen until the anchor has all the information necessary.

It could be as simple as raw text field that a wallet can choose to display or not. Max flex with min tech debt. Wdyt?

I'm for it. We can add it to the fee object in the GET /info response as "description".

JakeUrban commented 2 years ago

cc @tomerweller

tomerweller commented 2 years ago

I'm in favor of mostly not doing anything. Maybe add a note that the /fee endpoint is not applicable for cross asset transfers.

Support fees for transactions using quotes

I actually like this idea but it'll be hard to get this right and there's no sufficient evidence yet that there's enough demand and it's worth the effort. I do think it's worth revisiting in the future if/when we have a better understanding of various fee structures and the input they require.

Deprecate the GET /fee endpoint

The cost of deprecation is that we might be denying this functionality from anchors that this is applicable for.

We probably still need some way to still communicate the fees earlier so that the user knows what the fees could be before they signup with an anchor. It could be as simple as raw text field that a wallet can choose to display or not. Max flex with min tech debt. Wdyt?

Sounds good. This can be a failover for anchors that don't implement the /fee endpoint, right?

Bottom line is that a good wallet UX is conveying as much information as possible to the user before they enter the flow. I don't think should give up because of conforming to a lowest common denominator.

tomerweller commented 2 years ago

@leighmcculloch can you provide some examples of "good" raw text fee descriptions?