fedimint / fedimint

Federated E-Cash Mint
https://fedimint.org/
MIT License
536 stars 209 forks source link

Federation facilitates internal payments w/o involving gateway #613

Closed justinmoon closed 10 months ago

justinmoon commented 1 year ago

https://github.com/fedimint/fedimint/issues/461 implemented basic internal payments support by outsourcing it to the gateway. Perhaps we could have the sender buy the preimage directly from the federation?

Edit: Long, outdated original post https://github.com/fedimint/fedimint/issues/461 implemented basic internal payments support by outsourcing it to the gateway. But the gateway still charges a fee without really providing any service that the federation couldn't itself, which is worse from the user POV. Not sure if / when we want to implement this, but wanted to write down how we could do it just to share the knowledge: 1. Recipient creates an invoice. This basically sets up an account in the federation that they will be able to sweep once funds are deposited to it. 2. Recipient sends invoice to sender 3. Sender attempts to pay invoice. First step is depositing ecash into an `OutgoingContract` in the federation which is spendable by anyone who presents the preimage corresponding for this invoice. At this point the user would normally tell the gateway about this escrow contract and the gateway would go buy the preimage over lightning. But if the recipient's account is also in the federation, then the federation itself could just settle between the two accounts here. Notes: - It would do this by checking the database [here](https://github.com/fedimint/fedimint/blob/2e4a1d48cd1d0d659b6a71659e4b36bae36e79a4/modules/fedimint-ln/src/lib.rs#L317) for an `IncomingContract` with the same `hash` parameter as the `OutgoingContract`. If such a contract exists, deposit `invoice.amount` into the `IncomingContract` and `ContractOutput.amount - invoice.amount` to `ContractAccount` which the sender can sweep immediately. Otherwise, proceed as we currently do by funding the outgoing account. This way the federation wouldn't make any profit (which complicates things) and user wouldn't unnecessarily pay fees to the gateway. - Whatever fee the sender had deposited to the outgoing escrow account in excess of the invoice's amount could remain in this account and sender could sweep it back. This alleviates a previous concern voiced by @Kodylow and others that having the federation settle internally could lead to it making profit which just complicates things right now. - Clients that pay invoices (e.g. [ln-pay cli command](https://github.com/fedimint/fedimint/blob/2e4a1d48cd1d0d659b6a71659e4b36bae36e79a4/client/cli/src/main.rs#L454-#L481)) would need to be able to recognize that internal settlement happened. Before contacting the gateway perhaps they could check to see if their outgoing account already had `invoice.amount` deducted? Something like that ...
dpc commented 1 year ago

One of the concerns was privacy. If you hand over an LN invoice, now they could discover you are a member of the same mint by noticing that the payment behaves differently.

justinmoon commented 1 year ago

Another nuance here: if sender client can't tell that recipient is in the federation, the sender client will still need to select a gateway and display expected fees based on that gateway. If federation settled internally, then the client would need to express somehow that the fees user expected to pay were "refunded" or something along those lines ...

okjodom commented 1 year ago

the gateway still charges a fee without really providing any service that the federation couldn't itself...

Assuming the gateway has zero-fee policy for internal payments (or in general), would we still want to delegate market making services to the gateway or handle it directly within the mint?

dpc commented 1 year ago

But the gateway still charges a fee without really providing any service that the federation couldn't itself, which is worse from the user POV.

I don't think I can agree with the core premise here. LN Gateway provides a service of facilitating LN payments for the Mint. Just because it so happens that a particular payment can be short-circuited does not mean the gateway did not provide a service and should not be paid. Their costs (like locking up funds in channels and with mint) are largely aggregate, not per-payment, and we should accept the profit motive.

Doing federation matching at the federation level seems intuitively to me as special casing (complicating) something that should have been taken care of by just general market competition structure.

From a financial PoV mint is attempting to undercut LN Gateways and refund the user with a profit. The money gateways will not be able to make on internal payments now they will have to earn somehow differently (by charging higher fees elsewhere) anyway to justify their capital locked.

In net short-circuiting at mint level shifts the pricing negotiating power to the mint users in aggregate, but not as much as savings them all these fees, because gateways will just increase fees elsewhere because the market for being LN gateways is less lucrative now, so it attracts less competition. The equilibrium shifts a bit. Users who do mostly internal LN payments benefit, other users loose (higher outgoing payment fees and/or fewer gateways competing).

Ideally if a mint has multiple gateways, it should be possible for any of them to short-circuit the payment (is this the case? I don't know the details), which might largely have the same effect - keeping the fees on internal payments lower, as gateways compete for them. All without all the drawbacks.

dpc commented 1 year ago

Ideally if a mint has multiple gateways, it should be possible for any of them to short-circuit the payment

BTW. If this was the case, any mint member could be a LN gateway which can route internally undercutting anyone else, without opening any real LN channels to the outside world. Again - I don't even know if it's technically possible.

dpc commented 1 year ago

I also wonder if the similar result can't be achieved on a client side. Mint user could produce some kind of mint invoice that allows paying with any: ecash, LN, on chain, so short-circuiting would happen even earlier, with a more explicit choice of tradeoffs which would be up to a end application to drive.

okjodom commented 1 year ago

Ideally if a mint has multiple gateways, it should be possible for any of them to short-circuit the payment (is this the case? I don't know the details), which might largely have the same effect - keeping the fees on internal payments lower, as gateways compete for them.

True.

Additionally, a gateway that wants to route internal payments for a mint has to peg in with an amount 'X' closely related with (even limits?) the aggregate volume they can route. I don't know if this incentives gateways to higher fees, but whatever margin they collect is justified by this 'stake', essential to their operation as a gateway.

elsirion commented 1 year ago

I think the solution is much simpler:

  1. The client keeps a list of known gateways
  2. If an invoice it wants to pay names one of these as a route hint do the following:
  3. Fetch the offer from the federation and create an incoming contract from it (just as the LN GW would)
  4. Once the preimage is decrypted and the outcome of the incoming contract is available we have paid the invoice without ever creating an outgoing contract or paying any fees to the LN GW since we didn't use it at all.

Note that steps 1+2 are merely an optimization.

okjodom commented 1 year ago

If an invoice it wants to pay names one of these as a route hint do the following:

Gets complicated if the same gateway serves multiple mints. But maybe we could include a mint identifier in the route hint?

elsirion commented 1 year ago

But maybe we could include a mint identifier in the route hint?

We need to do that anyway since the GW wouldn't know which mint to ask otherwise.

okjodom commented 1 year ago

I think the solution is much simpler:

  1. The client keeps a list of known gateways
  2. If an invoice it wants to pay names one of these as a route hint do the following:
  3. Fetch the offer from the federation and create an incoming contract from it (just as the LN GW would)
  4. Once the preimage is decrypted and the outcome of the incoming contract is available we have paid the invoice without ever creating an outgoing contract or paying any fees to the LN GW since we didn't use it at all.

Note that steps 1+2 are merely an optimization.

IMO given guarantees of not making fees to the mint, it seems pretty natural to implement it this way. Assuming we agree on this solution for internal payments, the gateways are left to deal with

Should we spec out these two payment scenarios as a matter of proofing the direction we are taking for internal payments? Any gotchas or other non-obvious payment scenarios?

elsirion commented 1 year ago

self payments - special case of outgoing payments, where the gateway is directly bridging two mints

Note that this isn't even supported currently. We'd need to think about this problem in general, which would be a good separate issue. For the internal payment optimization we can just assume that a GW servers exactly one federation to keep the scope manageable (big PRs take longer and are harder to review, so whenever possible we should split tasks aka "divide et impera").

justinmoon commented 1 year ago

Gets complicated if the same gateway serves multiple mints.

If we had more random SCIDs (right now we just increment from zero), perhaps we could use that to filter?

justinmoon commented 1 year ago

One thing I just noticed -- the way we do it right now requires the gateway to have enough ecash on hand to buy the incoming contract themselves. This seems like kind of an unnecessary liquidity requirement.

elsirion commented 1 year ago

Ideally with the new LN client code we can just make the user buy the preimage directly from the federation if the route hint is a GW of the federation. @m1sterc001guy

m1sterc001guy commented 10 months ago

@okjodom we can close this one now right?