interledger / open-payments

Protocol to setup payments between entities on the Web based on GNAP
https://openpayments.dev
Apache License 2.0
215 stars 34 forks source link

Track WM provider balances with Sources #19

Closed wilsonianb closed 4 years ago

wilsonianb commented 4 years ago

Stripe has a Sources API whose general concept (specifically the receiver flow) could serve to track pooled web monetization provider balances while also being useful beyond just web monetization.

A source represents an amount paid (via push) to the receiving wallet that has yet to be charged / used to pay an invoice. With Stripe, the paid amount is not credited to the receiver's balance until charges are made (but uncharged amounts are automatically credited after 60 days). We may prefer to instead immediately credit the recipient's account balance with amounts paid to sources (as is currently the case for sessions).

In addition to the balance, a source would include an id and public key. In the case of web monetization, the id would be deterministically generated (based on the payment pointer and a wm provider-specific value), and the public key would belong to the wm provider. The recipient should require a token signed by the corresponding private key before spending against the source on a user's behalf.

A website could spend against a source via a PaymentRequest, so that a source would be just one possible PayHandler for web micropayments (and web monetization would be just one possible way fund a source).

While sources could just track pooled wm provider balances and sessions track individual session amounts, I think sources alone would adequately meet the needs of web monetization payment verification. Only tracking wm provider pooled balances prevents websites from discriminating between paying and non-paying users if a sufficient total amount has been collectively paid.

For wm users who are acting as their own provider, they would have the choice between

(^ similar to the distinction between reusable and single-use sources https://stripe.com/docs/sources#single-use-or-reusable)

Regarding how we prevent a single user from unfairly exhausting a provider's pooled balance(s) without also tracking session amounts, I think "Do we want pooled wm provider balances?" is a better question than "Do we want sessions with pooled wm provider balances?" since:

While wm providers can attempt to come up with a solution (maybe with anonymous tokens that the user passes to the website who consumes them with the provider before charging the source balance), I also think that with web monetization, how a website configures their pricing and rate-limiting becomes part of creating a good user experience, whether it's individual sessions or provider pooled balances being tracked.

See also: https://stripe.com/docs/sources/ach-credit-transfer <- I might prefer the name credit over source https://stripe.com/docs/billing/invoices/reconciliation#handling-exceptions

adrianhopebailie commented 4 years ago

@wilsonianb do you have any insight as to why Stripe has deprecated the Sources API?

We should probably find out to ensure we're not repeating mistakes they have already learned from

wilsonianb commented 4 years ago

It seems like the primary motivation for Stripe's newer APIs was driven by Strong Customer Authentication (SCA) for European card payments.

For example, SCA is a main factor for determining if a customer should use the newer PaymentIntents API: https://stripe.com/docs/payments/payment-intents/migration/charges#understanding-the-stripe-payment-apis

I think we'd really only be interested in the receiver flow for Sources API functionality, and all Stripe use cases for that flow (Mulitbanco, ACH credit transfers, and checks) still aren't supported by the newer APIs. See the far right column of the chart here: https://stripe.com/docs/sources#supported-payment-methods

https://stripe.com/docs/payments/ach-bank-transfers#payment-methods

We plan to support all payment methods on the Payment Methods API. ACH and SEPA debit payments are not yet supported. Use the Sources API for these payment methods in the meantime.

Need to use a payment method that’s not yet supported by the Payment Methods API? Use the Sources API instead. The main difference between the Payment Methods API and the Sources API is that sources describe transaction state through the status property, which means that each Source object must be transitioned to a chargeable state before it can be used for a payment.

https://stripe.com/docs/payments/payment-methods#transitioning

We are continually adding payment methods support on the Payment Methods API. In the meantime, the Sources API may be right for payment methods not yet supported on the Payment Methods API.

wilsonianb commented 4 years ago

https://stripe.com/docs/payments/payment-methods#transitioning

The main difference between the Payment Methods and Sources APIs is that Sources describes transaction state through the status property, which means that each Source object must be transitioned to a chargeable state before it can be used for a payment. In contrast, a PaymentMethod is stateless, relying on the PaymentIntent object to represent payment state.

While we also don't need a chargeable status property, I think we want a stateful resource that tracks the received and charged amounts. (I'm guessing that's why receiver flow use cases aren't supported by Stripe's new APIs.)

Considering how Stripe's Sources and PaymentMethods APIs deal with sourcing payments from disparate systems, whereas we're just concerned with ILP-to-ILP, I think there's a couple ways we could go about this:

  1. Have a receiver/credit resource that functions in the way this issue describes. Payer's can create or query it to get push details. Payee's can spend against it.
  2. Have a source/payment_method resource that can represent a receiver (push), a mandate (pull), or some future TBD method(s). This would be similar to how you can create a source with a receiver or mandate and would give us a way to represent a mandate at the receiving wallet.
sharafian commented 4 years ago

In addition to the balance, a source would include an id and public key. In the case of web monetization, the id would be deterministically generated (based on the payment pointer and a wm provider-specific value), and the public key would belong to the wm provider. The recipient should require a token signed by the corresponding private key before spending against the source on a user's behalf.

The recipient is referring to the site and not the wallet right? The wallet shouldn't be aware that the name of the source is a public key. And the authentication oughtn't be required to pay into the source so the wallet doesn't need to verify signatures on the pay in

wilsonianb commented 4 years ago

@sharafian All correct.

I was also considering making the sender / WM provider's payment pointer the source id, which would help with verifying the key used to sign the token, but that'd make things difficult for privacy-minded users acting as their own wm provider.

wilsonianb commented 4 years ago

@sharafian had the idea that push payments could only be made to this source/receiver/credit resource (not invoices).

An invoice could then be satisfied by "pulling" from a source or a mandate.

:thinking: On second thought, we'd still be pushing to invoices via mandates.

An alternative could be to push to a source even when "pulling" with a mandate. Then all pushes are to sources, and invoices are fulfilled by sources.

Here's some flows that totally remove invoices as resources on the receiving wallet :grimacing:: https://wilsonianb.github.io/diagrams/push-source https://wilsonianb.github.io/diagrams/pull-source

matdehaast commented 4 years ago

I think we want a stateful resource that tracks the received and charged amounts.

I think for me this sentence sums up what we are trying to encapsulate.

My main driver is to reduce complexity and make the API as clean and simple as possible. I think with what you propose @wilsonianb we could basically deprecate Invoices and just use the "source" resource proposed.

The main question I have is, do you believe we encapsulate the WM use case within the "sources" resource with minimal complexity?

wilsonianb commented 4 years ago

do you believe we encapsulate the WM use case within the "sources" resource with minimal complexity?

I think so.

A privacy conscious user acting as their own WM provider can create and pay to a source with the Monetization ID as the id. (I'm under the impression that we're fine having the site generate that id, possibly just as the PaymentRequestEvent id). The site wouldn't require a token to verify before spending from that source.

For pooling a WM provider's balance, the source id could instead be either a public key or the provider's payment pointer. (where jwks_uri can be located). Users would get signed tokens from their provider (https://github.com/adrianhopebailie/open-payments/issues/17#issuecomment-559276646), which would include the Monetization ID. The site would verify this token before spending against the source.

I think the latter would more closely resemble how non-WM use cases would work with this proposal of just sources and no invoices, in that the issuer produces a token after pushing to a source, which can be presented to the receiver, who should verify before spending against the source.

The privacy conscious WM user is just a special case where a token isn't necessary.

It seems like we can get away with the receiving wallet not having to deal with tokens in any cases (WM or otherwise). Senders wouldn't need to authenticate during source creation. It's just the receiver who determines if and how to verify tokens based on the use case / PaymentRequest method.

sharafian commented 4 years ago

the source id could instead be either a public key or the provider's payment pointer

The nice thing about doing a public key rather than a URL is that a privacy conscious user could generate fresh public keys every page load (pretty easy with ecc afaik) and then authenticate with the same scheme as everyone else. Otherwise you have the "signature" scheme where you look up a key with payment pointer and a "bearer" scheme where you authenticate with the token. Sites need to be aware of and support both and you could end up with sites that inadvertently support just one of the two schemes

An invoice could then be satisfied by "pulling" from a source or a mandate. On second thought, we'd still be pushing to invoices via mandates. An alternative could be to push to a source even when "pulling" with a mandate. Then all pushes are to sources, and invoices are fulfilled by sources.

The way I was thinking about this was that there's an act of "filling an invoice" which may or may not move actual funds. Sources and Mandates both "fill invoices." But I like the idea of scrapping invoices altogether and just using Sources

sharafian commented 4 years ago

Of course the downside of putting public key inline with a source's name is that you can't rotate the public key without losing the source balance

weird idea what if you could use a data url when you want the public key inline and a real URL when you want the ability to rotate the key?

adrianhopebailie commented 4 years ago

I'm concerned about the complexity we're adding here to accommodate tracking "spends". It's a very WM-specific requirement and I think we should define a different wallet API that deals with this if there is a need.

We are making assumptions (which have already changed once) about how websites want to track incoming money (by user, session, provider etc) and relate this back to consumption of content or services. That's up to them. We should just ensure that we expose as much info to them as possible so they have the flexibility to deploy whatever business rules make sense for them.

Our goal with Open Payments is to ensure that the receiving wallet is able to:

  1. Generate STREAM credentials that a sender can use to send it money
  2. Aggregate incoming payments in a way that suits the use case for their customers (websites, merchants etc)

How wallets expose this aggregated payment data to their customers is not in scope for Open Payments.

I realise we have included this in the current API specification because we argued that it was useful for the receiving wallet to provide this service to the receiver (website) but the requirements have changed and I don't think this is worth the complexity it adds.

All that said, I like sources (just not the name 😄). Here's my counter-proposal of how they could work:

Identification of the sending entity is where use cases vary.

In a privacy preserving use case like WM the JWS would identify the provider (or in the case of an entity being their own provider it would identify the sending wallet).

In a P2P payment use case or e-commerce it might identify the sender, either specifically (e.g. using some KYC compliant identifier as required) or using an identifier defined by the receiver (e.g. a customer number defined by the merchant).

For WM the flow is similar to what we have today except the provider sends a JWS to the receiving wallet when creating the source (analogous to SPSP today).

The receiving wallet now has two pieces of data it can associate with the source, the UUID (generated by the browser) and the provider's JWS.

It can expose APIs to the website that present the balance of funds received by source or aggregated by provider. It's up to the website to decide what they want.

sabineschaller commented 4 years ago

(A)

In addition to the balance, a source would include an id and public key. In the case of web monetization, the id would be deterministically generated (based on the payment pointer and a wm provider-specific value), and the public key would belong to the wm provider. The recipient should require a token signed by the corresponding private key before spending against the source on a user's behalf.

(B)

A privacy conscious user acting as their own WM provider can create and pay to a source with the Monetization ID as the id. (I'm under the impression that we're fine having the site generate that id, possibly just as the PaymentRequestEvent id). The site wouldn't require a token to verify before spending from that source.

I understand the need to have an id made up of wm-provider and user characteristics in (A) but I'm not sure I understand why there is the need for a signed token in (A) and not in (B). Is it because in (A) I could spoof an ID that the website uses to spend against a wm-provider pool? But then, why couldn't that be spoofed in (B)? On the other hand, we don't want users to have to create signed tokens.

For wm users who are acting as their own provider, they would have the choice between

  • making the most of what they pay and pooling their balance for a payment provider at a single source

How would they do that without a token from a wm-provider?

wilsonianb commented 4 years ago

@adrianhopebailie

I'm concerned about the complexity we're adding here to accommodate tracking "spends". It's a very WM-specific requirement and I think we should define a different wallet API that deals with this if there is a need.

How wallets expose this aggregated payment data to their customers is not in scope for Open Payments.

:+1: Receivers could get by doing accounting themselves by matching source balance amounts at their wallet with internally tracked invoices/sessions/etc. Their wallet can make that easier by offering "spend"-like functionality, which I agree is out of scope.

We are making assumptions (which have already changed once) about how websites want to track incoming money (by user, session, provider etc) and relate this back to consumption of content or services. That's up to them. We should just ensure that we expose as much info to them as possible so they have the flexibility to deploy whatever business rules make sense for them.

I've been thinking about it in terms of how the sender wants their paid amount to be tracked. Does it have to be something decided by the receiver? Or can we just have the receiver be happy to verify that they've been paid a certain amount by a sender regardless of how amounts paid by that sender are aggregated at the wallet?

Identification of the sending entity is where use cases vary.

Could identification also be out of scope for Open Payments? It seems like the token given to the receiver by the sender should satisfy whatever specific criteria the receiver has for the particular use case. Allowing the payment pointer, public key, etc to be the resource id (1) makes the wallet oblivious to the identification and (2) let's the receiver verify the sender's identity before having to query the source.

I like sources (just not the name :smile:)

Could we call it a balance? :thinking:

sharafian commented 4 years ago

Apologies for the text wall

@adrianhopebailie:

How wallets expose this aggregated payment data to their customers is not in scope for Open Payments.

I see this part as important to standardize. The whole point of ILP is a neutral way to do payments that decouples the "how" from the "who." If the APIs that Interledger applications consume don't have any standard functionality, then you'll just get trapped with a wallet provider.

  • A source has a balance which only ever goes up. It is an accumulation of funds received from the source
  • A source has a unique identifier (UUID) which never changes

If a source sticks around forever (as in per-provider accounting) then it is certainly easier to manage the current state (spending) from the site's own backend.

But we have discussed at length how hard it is to synchronize the state of a temporary object in the wallet with another temporary object in the site's backend. And if some visitors are creating new sources on every page load then it might not be possible to keep all the sources around forever.

In a privacy preserving use case like WM the JWS would identify the provider (or in the case of an entity being their own provider it would identify the sending wallet).

Pooling based on sending wallet would be odd because you're offering to subsidize other visitors just because they use the same wallet as you. A user should be able to be fully anonymous if they want to, and use a completely different identity on every page visit.

  • the provider gets a request from the browser to start streaming money to a Payment Pointer. The request has a WM Request ID (UUID) generated by the browser.
  • the provider determines the sources endpoint URL from the payment pointer and creates a source at the receiver wallet passing its JWS in the header and the WM Request ID as the identifier
  • the response provides a URL for the new source resource and the STREAM credentials to pay into the source

In the current implementation the provider never terminates any STREAM connections, and that would be the recommendation for future providers because it's favorable to privacy. That would require the client to prefetch quite a lot of JWS. We should make sure the JWS doesn't include the UUID or the site URL so that they're possible to pre-fetch. The client would also want to request these in some kind of blind way.

I'm still not entirely sure why the hard requirement on authenticating in order to pay to a source. Why not say anyone can pay to the source? The receiver could still verify some kind of signature before they deduct from that source's balance (in their own systems) for you

It can expose APIs to the website that present the balance of funds received by source or aggregated by provider. It's up to the website to decide what they want.

On my above point, I still think we should still standardize this API to enable switching between wallet providers easily. Besides, wallet providers don't know that much about how to make a nice API on top of Interledger, so doing that design ourselves decreases the chances of some kind of mistake

@sabinebertram:

For wm users who are acting as their own provider, they would have the choice between making the most of what they pay and pooling their balance for a payment provider at a single source How would they do that without a token from a wm-provider?

A token from a WM provider is required to spend from a WM provider's balance, but if you pay yourself you can basically create a "WM provider balance" on the fly. Because you created it, you can authorize yourself to spend against it.

wilsonianb commented 4 years ago

@sabinebertram

I'm not sure I understand why there is the need for a signed token in (A) and not in (B)

For (A), a WM provider signing a token which contains a site generated monetization id helps make sure tokens aren't reused, which would allow a single user to overspend the provider's pooled balance.

For (B), not using a token does put the user at risk of someone determining the site generated monetization id and submitting it to the receiver (before the user) as proof of payment for some other expense. It'd probably be fine and more consistent to also use a token.

How would they do that without a token from a wm-provider?

What Ben said (faster than me), they could store a public key or their payment pointer (for the jwks_uri) on the source and self sign. They'd use their own key as opposed to a WM provider having key(s) to sign tokens on behalf of all their users.

All that said, it's starting to sound like these details might belong in the web monetization spec instead of here.

sabineschaller commented 4 years ago

A token from a WM provider is required to spend from a WM provider's balance, but if you pay yourself you can basically create a "WM provider balance" on the fly. Because you created it, you can authorize yourself to spend against it.

I guess I misunderstood it the first time. I thought the idea was that a privacy-focused user acting as their own provider pools with users from another provider. I see now that you are talking about a pool per site vs a new source per visit.

Pooling based on sending wallet would be odd because you're offering to subsidize other visitors just because they use the same wallet as you. A user should be able to be fully anonymous if they want to, and use a completely different identity on every page visit.

100%

kincaidoneil commented 4 years ago

We are making assumptions (which have already changed once) about how websites want to track incoming money (by user, session, provider etc) and relate this back to consumption of content or services. That's up to them. We should just ensure that we expose as much info to them as possible so they have the flexibility to deploy whatever business rules make sense for them.

I see this part as important to standardize. The whole point of ILP is a neutral way to do payments that decouples the "how" from the "who." If the APIs that Interledger applications consume don't have any standard functionality, then you'll just get trapped with a wallet provider.

I very strongly agree with @adrianhopebailie with respect to spends. Even if we standardize an API for merchants to perform spends, I'm still skeptical that there wouldn't be lock-in. Providers will probably also expose the APIs given by the node implementation (which may provide more functionality on top of the Open Payments API), and some providers may even implement their own additional APIs to better accommodate particular use cases or customers.

What we're trying to accomplish here is very different from a traditional SaaS. We're trying to get multiple, competing SaaS companies (providers) to all expose the same API... when, to some extent, they can compete on the ease of use and functionality of each API they offer!

In framing this problem, I think we should differentiate between infrastructure providers and liquidity providers. Theoretically, we could have a flow where:

  1. Merchant goes to infra provider and creates an account. The infra provider deploys a dedicated Interledger node in the cloud for them, and exposes access to a slick admin dashboard (so the merchant doesn't have to deal with any of that infrastructure, though they could self-host if they wanted to).
  2. The admin dashboard populates a list of liquidity providers to peer with. The merchant selects one of them, which kicks off an OAuth flow to the liquidity provider to create an account, do KYC/AML, and setup billing. And boom... they're able to accept payments over Interledger.
  3. The merchant uses the HTTP API exposed by the hosted node to integrate payments with their app or service, probably using the infra provider's guidance and documentation.

The key ideas here:

TL;DR the interface between provider & merchant most interoperable and least likely to be subverted by lock-in is... Interledger! But, there are still ways to provide a great user experience for merchants.

sharafian commented 4 years ago

@kincaidoneil

I very strongly agree with @adrianhopebailie with respect to spends. Even if we standardize an API for merchants to perform spends, I'm still skeptical that there wouldn't be lock-in. Providers will probably also expose the APIs given by the node implementation (which may provide more functionality on top of the Open Payments API), and some providers may even implement their own additional APIs to better accommodate particular use cases or customers.

It's true that there's no stopping people from offering non-standard features. And it's definitely not a bad thing that additional APIs are available.

But there are some strong reasons aside from lock-in to have some core APIs shared between all providers even if they have more functionality on top.

For one, creating APIs is hard work. Especially with a standard like Interledger that wallets are not very familiar with. If we're getting multiple different wallets on Open Payments/ILP, we don't want to make every one of them invent an API. We're in a good position to offer a standard API that wallet providers can implement to give their users the most important features.

Secondly, we may want to delegate access to receiver side APIs (managing/querying sources, invoices, etc.), which requires some standardization. With delegated access, sites like cinnamon could embed a user's payment pointer on their video pages and then check with the user's wallet in order to ensure payment before video is served. Or even a self-hosted CMS could let users enter their payment pointer and then grant delegated access to easily provide server-side payment verification. Same goes for merchant use cases, where an ILP-based retail payment processor could be granted access to your wallet account and then give you widgets to put in your site for ILP checkout.

The interface between the liquidity provider and merchant is Interledger and does not depend on any proprietary API, so there's low switching costs (the merchant could even create accounts with multiple providers!).

That's a good idea; you're right that by far the most practical way to prevent lock-in is by giving people Interledger access directly to implement whatever APIs on top.

I think we could make this simpler than splitting the existing paradigm of wallet providers into two types of providers, infra and liquidity. Rather you could wallet providers offer both infra and liquidity at once, but ensure that one of the APIs included is direct ILP access (BTP uplink or ILP-HTTP). Then if you want to solely use the wallet as your liquidity provider, you could run your own ILP infra and peer it. You could open several wallet accounts and peer with all of them if you like, dynamically choosing the uplink with the best rates.

We may want to think about features like tier 1 Interledger peering for wallet customers, allowing them to create their own ILP address prefix.

The nice thing about using the wallet provider for this is that it gives an easy onramp for people who don't care about renting their own infra and it also gives a place for the wallet to perform KYC and any other regulatory checks at account creation.

kincaidoneil commented 4 years ago

creating APIs is hard work. Especially with a standard like Interledger that wallets are not very familiar with. If we're getting multiple different wallets on Open Payments/ILP, we don't want to make every one of them invent an API

Agree, but wallets won't have to: they're just going to use whatever ILP node software exists, and we can and should still implement APIs for merchants to manage payments within the node implementations (it just doesn't require standardizing them).

Also, it's only natural for a competitive provider to improve upon those existing APIs to make it simpler or more tailored for their customers' use cases.

Secondly, we may want to delegate access to receiver side APIs (managing/querying sources, invoices, etc.), which requires some standardization. With delegated access, sites like cinnamon could embed a user's payment pointer on their video pages and then check with the user's wallet in order to ensure payment before video is served

I don't know all of the business requirements or existing constraints for Coil and Cinnamon, but I question if we even need to standardize sources/invoices for that use case. An alternative flow:

  1. Cinnamon sends ILP packets to the user's wallet or WM provider. The user's wallet or WM provider pays out by sending those packets through the greater Interledger network, to the creator's wallet.
  2. Cinnamon would implement its own database to track creators' payment pointers (and maybe a minimum rate each creator is willing to accept for their videos). When a user visits a video, Cinnamon determines the amount/rate it needs to get authorization for, then might use e.g. a registered PaymentHandler to kick off an OAuth flow to the user's wallet, where the user would authorize delegated Interledger access to Cinnamon to initiate a payment for that content.
    • In this model, the wallet/Coil/the WM provider would be responsible for rate limiting Cinnamon however it sees fit and forwarding packets sent by Cinnamon.
    • Would there be a way to make this work for Coil or WM providers that have a special relationship with Cinnamon to automate this flow/negotiate how much bandwidth is available?
    • (Since in this case Cinnamon would be creating e.g. a direct ILP-over-HTTP connection with Coil, would this obviate the need to standardize how payments through a single WM provider are pooled, since Cinnamon and Coil could to negotiate their own method to authenticate & manage that?)
    • Since there's no settlement or liabilities created between Cinnamon & the payer (the user's wallet or Coil), would that prevent the wallet or Coil from being considered an MSB?
  3. After initiating the payment, Cinnamon's STREAM sender tracks how much has been paid, and begins serving the video after enough money has been fulfilled. (As noted earlier, Cinnamon's Interledger infrastructure could be hosted by a separate infrastructure provider).

The advantage of this approach is it only requires spec'ing a minimal API and OAuth flow to peer Interledger connectors and delegate access. Cinnamon can create it's own notion of an "invoice" or how much it needs paid out before it begins serving content, instead of us more rigidly defining that. (The creator is trusting Cinnamon to enforce that they're paying out the correct amount).

Cinnamon and the wallet/WM provider together determine the rate: Cinnamon can try to send as much money as it wants, but it's limited by the bandwidth authorized with the wallet or WM provider. Also, since Cinnamon controls the STREAM sender, they have control to stop the stream when the user pauses the video, for example.

@sharafian Would a flow like this work for Coil? Are there are concerns or issues with e.g. Cinnamon initiating the stream?

sharafian commented 4 years ago

@kincaidoneil

Cinnamon sends ILP packets to the user's wallet or WM provider. The user's wallet or WM provider pays out by sending those packets through the greater Interledger network, to the creator's wallet.

I think that's a really interesting idea. It has some nice properties like payment going directly to the creator while Cinnamon still has the ability to verify, and the ability to do per-provider accounting easily.

It does raise the barriers to becoming a Web Monetized site, where a server-side component is now required. Even though most serious sites will have server-side logic around WM, it's still a meaningful barrier for smaller sites and also hurts the ability to throw WM onto a static site. I know a infra provider of some kind could make that easier but I think the idea of renting infrastructure is out of reach for most people. Signing up at a wallet is something people understand; maybe if it were something their wallet could do automatically with no configuration it would be more feasible.

Cinnamon would implement its own database to track creators' payment pointers (and maybe a minimum rate each creator is willing to accept for their videos). When a user visits a video, Cinnamon determines the amount/rate it needs to get authorization for, then might use e.g. a registered PaymentHandler to kick off an OAuth flow to the user's wallet, where the user would authorize delegated Interledger access to Cinnamon to initiate a payment for that content.

I don't think it makes sense for Cinnamon to request an amount. Because there's no user interaction, anybody requesting money from Coil's automated agent will get really good at figuring out the maximum amount they can be granted. It's a game that doesn't really benefit anyone compared with just giving Cinnamon the amount we're comfortable letting them spend and not having them tell us what they want up front.

Requiring user interaction is certainly a dealbreaker but I think this can work without that. Perhaps Web Monetization would get the credential into the page and PaymentHandler could be used once there's a version with no user interaction for that particular request.

After initiating the payment, Cinnamon's STREAM sender tracks how much has been paid, and begins serving the video after enough money has been fulfilled. (As noted earlier, Cinnamon's Interledger infrastructure could be hosted by a separate infrastructure provider).

I do really like this property of it. It nicely sidesteps the requirement for a wallet to do complicated accounting and makes it easy for Cinnamon to figure out what payments are for because they're the ones sending them.

@sharafian Would a flow like this work for Coil? Are there are concerns or issues with e.g. Cinnamon initiating the stream?

One problem not mentioned above is privacy; if I'm linking all the sites I visit back to my provider then that hurts privacy. I could theoretically link them to some anonymous identifier (we're working on a scheme that lets you create anonymous tokens authorized for a minute of bandwidth each) but then cinnamon has to juggle creds all the time and it makes the backend more complicated.

Another problem is that sites will get this token and spend for all its worth right away. The bandwidth could be constrained but if it's still valid when you tab out of the page then they're still getting more than they deserve. You could have the browser/extension tell the provider when a page is or is not foregrounded and then the provider can adjust/turn off bandwidth of the tokens based on those events but it's a complicated flow.

These could theoretically be solved by saying you put a modicum of trust in the site that you delegate access to but I don't like the idea of WM having two flows ('normal' and 'delegated'). Our "Sign in with Coil" functionality is only a polyfill, even though it works kinda similarly to this proposal.

Overall I'm definitely going to be thinking about this because it solves some hard problems like payment verification and per-provider accounting. Probably some part of it could be used


Agree, but wallets won't have to: they're just going to use whatever ILP node software exists, and we can and should still implement APIs for merchants to manage payments within the node implementations (it just doesn't require standardizing them).

This isn't really a future-tense thing; the wallets currently implementing ILP are mostly running the JS connector and running some custom STREAM servers to manage accounting. APIs (right now just SPSP) are being written on top of that. For them it's more desirable than running a single package because they have more control and they can make it fit into their existing systems more smoothly.

I'd be interested in chatting more about this though and what those of us in the ILP ecosystem can do to make things easier for wallet implementors. I'd love for our work here to be aligned; if you're building ILP tools we could talk about ways to get them to wallets.

matdehaast commented 4 years ago

@kincaidoneil

In framing this problem, I think we should differentiate between infrastructure providers and liquidity providers

This is the wrong framing for Open Payments IMO. Open Payments is trying to achieve interoperability on two layers. First is Wallet-to-Wallet and second is Wallet-to-User/Merchant/Delegated Party. The wallet-to-wallet is achieved through the ease of discovery and resource definitions. Whilst the Wallet-users/merchant/DP comes from having a common interface for performing payments.

@kincaidoneil thanks for the alternative flow model description. That is very much what we envisioned initially with loop-back. The flow using the API approach is very similar to what we have for 3PPI shown in https://openpayments.dev/docs/3ppi.

Whilst I agree 100% this solves many issues from the merchant/user perspective. It adds lots of complexity into the upstream wallet/WM Provider. Complexity that I worry will make it almost impossible for us to convince them to implement. I will stress again, some wallets who are currently ILP enabled are not evening looking to give RAW ILP BTP access because the threat model is not fully understood. This is the whole reason we came full circle and made open payments an API layer above STREAM. Because it is much easier for wallets to grasp and fits better into the current way they do accounting internally.

And brings me back to a point I want to make. I am certain the solution we come up with won't be perfect because ultimately we there are many unknown-unkowns, which are impossible to design against. The reality is that for Interledger to grow this year we need to get Wallet partners beginning the process of implementing this stuff. This, in my opinion, requires us providing something that is familiar to them which is API's. Once we begin winning partners over we can iterate. I am not suggesting we rush this but ultimately we need to push this over the line because some partners are soon to begin implementing things and if we don't have something concrete its going to make people more hesitant down the line.

kincaidoneil commented 4 years ago

@sharafian

I don't think it makes sense for Cinnamon to request an amount. Because there's no user interaction, anybody requesting money from Coil's automated agent will get really good at figuring out the maximum amount they can be granted. It's a game that doesn't really benefit anyone compared with just giving Cinnamon the amount we're comfortable letting them spend and not having them tell us what they want up front.

For Coil's case, that makes sense. But I think to support prepaid wallets, there should also be a price set by the creator with user interaction to authorize it (why would the creator want to accept any arbitrarily small amount?). On Cinnamon's end, they could offer the ability for creators to set a price/rate, but also let them select which WM providers they want to accept payments from without any fixed or known rate. That way, if a creator decides Coil's payouts are worth their while, they can opt in; or, if they think they're too low, they can opt out. On Cinnamon's end, they would just disable/ignore the STREAM sender accounting when they know they're sending a payment through one of these enabled WM providers.

One problem not mentioned above is privacy; if I'm linking all the sites I visit back to my provider then that hurts privacy.

Good point (seems like this is a pretty hot-button issue).

One privacy property of using the Interledger layer rather than application layer is it seamlessly enables delegated delegated access. Anyone could develop a browser extension that authenticates with the user's wallets and/or WM providers, which they could delegate full access to. Then, that browser extension would delegate more limited access to each website or merchant. The extra layer of delegated access prevents leaking the details of each invoice or site visited to the wallet or provider.

This may not work for Coil, but if the privacy pitch was, "sure, you can use our browser extension, but if you don't trust us, you can also choose from any of these other browsers/extensions that support us without leaking your history" might be compelling.

Unfortunately, if the website was not making a direct peering connection with Coil, now they wouldn't know whether to account for the payment differently. It seems like there's some inherent tension between sharing which sites I visit and authenticating payments to those sites. How does the idea for anonymous tokens work?

I'd be interested in chatting more about this though and what those of us in the ILP ecosystem can do to make things easier for wallet implementors. I'd love for our work here to be aligned; if you're building ILP tools we could talk about ways to get them to wallets.

Yes, would love to chat more. On Xpring's end, we're very keen to add Open Payments to the Java implementation and enable more seamless payments between wallets.

kincaidoneil commented 4 years ago

@matdehaast

It adds lots of complexity into the upstream wallet/WM Provider.

What kind of complexity if it's all standard with the node implementation?

Complexity that I worry will make it almost impossible for us to convince them to implement. I will stress again, some wallets who are currently ILP enabled are not evening looking to give RAW ILP BTP access because the threat model is not fully understood.

Admittedly I haven't talked with wallets, and their opinion is valuable. But I'd push back on this: the threat model becomes much more complicated when we push this to higher layers. I just worked on Rust STREAM and looked at implementing pay-by-destination-amount, and oh my gosh is this hard to implement securely. The STREAM sender's state machine has so many more vectors that could potentially bypass accounting. This must be included within the wallet's threat model: the security of the Open Payments API depends on the security of the layers below it.

By contrast, the ILP layer threat model is much more intuitive: all packets flow through a single middleware/service pipeline. You could literally point to < 100 lines of code and say, as long as this guarantees certain balance/bandwidth limits, this is probably pretty secure (of course there are asterisks here, but far fewer than the STREAM case).

I am certain the solution we come up with won't be perfect because ultimately we there are many unknown-unkowns, which are impossible to design against. The reality is that for Interledger to grow this year we need to get Wallet partners beginning the process of implementing this stuff. This, in my opinion, requires us providing something that is familiar to them which is API's.

We're 100% in agreement on this. I'm just saying, let's formally spec & standardize the Wallet-to-Wallet setup API, and let's also design what one Wallet-to-User/Merchant/Delegated Party API might look like, but just not standardize it between implementations. (It might even enable us to iterate faster that way!)

matdehaast commented 4 years ago

@kincaidoneil

What kind of complexity if it's all standard with the node implementation?

All partners we have currently dealt with still want to intergrate Interledger into their existing accounting frameworks. In your model the wallet would need to have a cashin/cashout option to these specific Interledger accounts. Whilst I agree that would be the ideal case, in reality that is not how the current partners are operating.

By abstracting Open Payments to the STREAM API level only, we allow them to do that accounting in the same way they are doing it now. An example would be a user that wants to send $1

  1. The user would instruct the wallet to send $1.
  2. The wallet would deduct $1 from the specific account.
  3. The wallet would initiate a STREAM payment for $1.
  4. If successful all is fine, if it was a partial payment or complete failure the wallet would credit the users account by whatever it needs to.

pay-by-destination-amount, and oh my gosh is this hard to implement securely.

Agreed there is much complexity still to be dealt with regarding STREAM. And some of Open Payments open questions around how fees are built into our spec still need to be addressed. For now we assume the mandates etc are for sending amounts and not receiving amounts. This may be flawed in the sense the merchant/receivers are absorbing the fees. But that is probably the best way to deal with it for now.

By contrast, the ILP layer threat model is much more intuitive: all packets flow through a single middleware/service pipeline. You could literally point to < 100 lines of code and say, as long as this guarantees certain balance/bandwidth limits, this is probably pretty secure (of course there are asterisks here, but far fewer than the STREAM case).

Whilst both you and I can agree on that point, the reality is different. We currently have 3 wallets who have ILP enabled of which only 1 is running their own node. It is easy to forget what we know and have learnt. Interledger does take time to grasp. We need to be cognizant of that fact.

We're 100% in agreement on this. I'm just saying, let's formally spec & standardize the Wallet-to-Wallet setup API, and let's also design what one Wallet-to-User/Merchant/Delegated Party API might look like, but just not standardize it between implementations. (It might even enable us to iterate faster that way!)

Having been involved in the discussion with wallet partners my feeling is standardizing the later API is needed to aid adoption. I will state, my angle is optimizing for adoption. Whatever enables that faster is what I value most and I don't have any gripe on the strict technical aspect of your proposal.

We need to take a position of if we should standardize both API's or just the setup. Will create a new issue as this one is getting hijacked.

sabineschaller commented 4 years ago

For now we assume the mandates etc are for sending amounts and not receiving amounts. This may be flawed in the sense the merchant/receivers are absorbing the fees.

I think this is not new but the current status quo. Whenever we buy something, the merchant prices in fees, e.g. paypal fees. So why shouldn't ILP fees be priced in? Because they could be very volatile?

matdehaast commented 4 years ago

@sabinebertram correct it is the current status quo. My wording wasn't great but what I meant was that we could attempt later to find a model that allows fix receiving but we should consider it out of scope for now