New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recurring Subscription Models are a Good Thing and should be viable on Ethereum (Merit + Architecture ERC) #948

Open
owocki opened this Issue Mar 25, 2018 · 81 comments

Comments

Projects
None yet
@owocki

owocki commented Mar 25, 2018

I am opening this ERC as a means of discussing (a) the merits and (b) the viability of creating a standard way of managing recurring payments on the blockchain, both (1) for tokens, and (2) for Eehereum.

Merit

Monthly subscriptions are a key monetization channel for legacy web, and arguably they are the most healthy monetization channel for businesses on the legacy web (especially when compared to ad/surveillance) based models. They are arguably more healthy than a token based economic system (depending upon the vesting model of the ICO).

For these reasons, I think it's worth talking about the viability of creating a standard way to do 'subscriptions' on Ethereum. I'm envisioning an

From UX standpoint, it would be pretty nice if you could manage all your ethereum-based SAAS subscriptions from one service like an on-chain keychain, if privacy was respected.

Viability

Opt in every month model

This is already viable if a service were to send an email (or other notification) to a user to every month sign a transaction.

But it creates a lot of churn in the subscriber base because the steps of

  1. sending the email.
  2. receiving the email
  3. opening the email
  4. signing a tx
  5. broadcasting the tx

is a lot of friction for the user.

It is also suboptimal from a cash flow perspective from the business, because the trickle of exchange of a value to the user and revenue for the business requires each party to reaffirm their relationship every month.

In a world in which there are 100s of Ethereum based dapps, it would simply be untenable from an attention standpoint for a consumer to manage all of their subscriptions in this world.

Opt out model

For the above reasons, I think it's optimal for Ethereum to support opt out subscription models. I am defining an opt out subscription model as

  1. User consents to having price worth of ETH (or tokens) withdrawn every time_period by service_address.
  2. The user may remove consent at any time.
  3. The owner of service_address may remove price worth of ETH/tokens every time_period. If those tokens are available and the users consent is active and its been at least time_period since last withdrawal, then the tx will be successful. If not it will throw().

Case Studies

Take the case study of Adobe Creative Cloud. Prior to 2013, you had to pay $1000 for creative suite, and it was a massive barrier to entry. Now you just pay $40 per month, and you can learn the software and continue to pay if you use it. And Adobe can manage their cash flow over time.

Or the case of Amazon Prime. For $80 per year, one can simply (1) not have to pay shipping for their goods (2) receive a ton of benefits related to their content. And now amazon can do revenue forecasts more accurately because they're managing a consistent voume of cash flow.

virtuous-cycle-of-the-saas-business-model-e1497454519597

Technical Viability

Right now, it is not technically viable to do opt out recurring subscriptions on the blockchain. The best workaround would be to present a user with an approve(x) where x = price * n, where price is the monthly price of the service and n is a number of months, and then call transfer(x/n) every month or so.

Until (and if) ETH becomes a token, it would not be viable to do this at all with ETH.

Proposal.

I am not at a point yet with this idea where I feel comfortable presenting an interface. A discussion on (a) merit should precede the discussion on viability and proposal design.

My only strongly held beliefs for the 'proposal' stage of this ERC at this point is

  1. that subscription payments are a core piece of infrastructure for the Ethereum ecossytem and thereby should not be subject to the rent-seeking nature of any tokenized product (other than gas payments setup already active in the Ethereum protocol)
  2. The system should be architected such that a subscription product can be managed in a completely trustless way. (i.e. no trusted intermediary in between the two parties).

👋
@owocki and the @gitcoinco team.

@djosey

This comment has been minimized.

Show comment
Hide comment
@djosey

djosey Mar 25, 2018

I like this. SAAS subscriptions aren't usually just a binary thing where they're just either active or not -- you might pick a service level or price point or number of users or whatever options to configure the sub & maybe that's done in the service's traditional web application. But it seems like if you're basically signing a contract, the various terms beyond whether the sub is active/inactive as well as pricing details etc should be somehow linked to this abstraction for the purpose of recording what the user signs for. So, to break it down, it seems to me like you could have terms parameters(which could be adjusted potentially with implications on payment), payment calculation, and a signature working together on this. Although for an MVP, would probably be good to just focus on as though the terms are just binary -- user is subscribed, user is unsubscribed.

djosey commented Mar 25, 2018

I like this. SAAS subscriptions aren't usually just a binary thing where they're just either active or not -- you might pick a service level or price point or number of users or whatever options to configure the sub & maybe that's done in the service's traditional web application. But it seems like if you're basically signing a contract, the various terms beyond whether the sub is active/inactive as well as pricing details etc should be somehow linked to this abstraction for the purpose of recording what the user signs for. So, to break it down, it seems to me like you could have terms parameters(which could be adjusted potentially with implications on payment), payment calculation, and a signature working together on this. Although for an MVP, would probably be good to just focus on as though the terms are just binary -- user is subscribed, user is unsubscribed.

@jrmoreau

This comment has been minimized.

Show comment
Hide comment
@jrmoreau

jrmoreau Mar 25, 2018

Do you feel you'd want to make sure the user signed a transaction associated with the subscription every time a payment was due? This is basically like a double opt-in, which is better for the consumer. If they don't approve/sign the transaction requesting, the service or product does not go to them. Out-out by default?

jrmoreau commented Mar 25, 2018

Do you feel you'd want to make sure the user signed a transaction associated with the subscription every time a payment was due? This is basically like a double opt-in, which is better for the consumer. If they don't approve/sign the transaction requesting, the service or product does not go to them. Out-out by default?

@eshon

This comment has been minimized.

Show comment
Hide comment
@eshon

eshon Mar 25, 2018

Maybe this was already in the plan but yeah it'd be nice ux to have a subscription registry service for all your subscriptions (with updates aggregated in 1 sweep / notification / single monthly or annual transaction by the user then auto-paid to each service). Might be more of a dapp tho like http://scroogeup.com or a budgeting app or advanced wallet but maybe it could be an ERC.

eshon commented Mar 25, 2018

Maybe this was already in the plan but yeah it'd be nice ux to have a subscription registry service for all your subscriptions (with updates aggregated in 1 sweep / notification / single monthly or annual transaction by the user then auto-paid to each service). Might be more of a dapp tho like http://scroogeup.com or a budgeting app or advanced wallet but maybe it could be an ERC.

@ptrwtts

This comment has been minimized.

Show comment
Hide comment
@ptrwtts

ptrwtts Mar 25, 2018

For the case of tokens, couldn't you do something similar to 0x, where you give an unlimited allowance to a smart contract which has clearly bounded functionality (to only allow withdrawals of amounts you approve, on a certain interval)?

  • Service deploys a smart contract that can withdraw tokens from users (or even better, it's a shared contract for all subscriptions). The contract could be audited to see that it will only withdraw amounts that the user approves
  • The user "approves" the contract for an unlimited allowance
  • The user calls the createSubscription() function, allowing price tokens to be withdrawn from them every time_period by service_address, until they cancel
  • Every month, the service_address calls withdrawSubscription(), which uses transferFrom() to collect the tokens that have been authorized

This would allow the user to authorize an ongoing subscription with one-time setup, and no need to escrow funds. Would this satisfy your requirements?

Doing this with ETH is probably harder, as there's nothing like the "approve" function that I'm aware of.

ptrwtts commented Mar 25, 2018

For the case of tokens, couldn't you do something similar to 0x, where you give an unlimited allowance to a smart contract which has clearly bounded functionality (to only allow withdrawals of amounts you approve, on a certain interval)?

  • Service deploys a smart contract that can withdraw tokens from users (or even better, it's a shared contract for all subscriptions). The contract could be audited to see that it will only withdraw amounts that the user approves
  • The user "approves" the contract for an unlimited allowance
  • The user calls the createSubscription() function, allowing price tokens to be withdrawn from them every time_period by service_address, until they cancel
  • Every month, the service_address calls withdrawSubscription(), which uses transferFrom() to collect the tokens that have been authorized

This would allow the user to authorize an ongoing subscription with one-time setup, and no need to escrow funds. Would this satisfy your requirements?

Doing this with ETH is probably harder, as there's nothing like the "approve" function that I'm aware of.

@niran

This comment has been minimized.

Show comment
Hide comment
@niran

niran Mar 25, 2018

Recurring payments are very important. One unaddressed issue in this model is volatility. For users to grant price-based withdrawals to a contract, the oracle needs to be able to disable withdrawals during periods of high volatility.

niran commented Mar 25, 2018

Recurring payments are very important. One unaddressed issue in this model is volatility. For users to grant price-based withdrawals to a contract, the oracle needs to be able to disable withdrawals during periods of high volatility.

@ScottStevenson

This comment has been minimized.

Show comment
Hide comment
@ScottStevenson

ScottStevenson Mar 26, 2018

Love this idea. An important discussion to have is whether this should be baked into Ethereum or whether this should be it's own project built on top of Ethereum.

Personally I believe it's so critical to the development of the dapp ecosystem that a core standard or new functionality that enables this sort of subscription with a consistent method that the user can understand, is warranted.

One difference to note in the model discussed here and the typical model is that the credit card model uses credit - you don't need to have money sitting on your credit card for payments to go through - and many people (if not most) do manually pay their credit cards. So you could envision a model where multiple apps request charges and then a user can approve them at all at once at the end of each month. Apps could decide themselves how long to allow the user to go without approving.

But maybe that's pointlessly carrying over the legacy mechanics.

ScottStevenson commented Mar 26, 2018

Love this idea. An important discussion to have is whether this should be baked into Ethereum or whether this should be it's own project built on top of Ethereum.

Personally I believe it's so critical to the development of the dapp ecosystem that a core standard or new functionality that enables this sort of subscription with a consistent method that the user can understand, is warranted.

One difference to note in the model discussed here and the typical model is that the credit card model uses credit - you don't need to have money sitting on your credit card for payments to go through - and many people (if not most) do manually pay their credit cards. So you could envision a model where multiple apps request charges and then a user can approve them at all at once at the end of each month. Apps could decide themselves how long to allow the user to go without approving.

But maybe that's pointlessly carrying over the legacy mechanics.

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Mar 26, 2018

So, to break it down, it seems to me like you could have terms parameters(which could be adjusted potentially with implications on payment), payment calculation, and a signature working together on this.

This is a neat idea.. I hadnt even though of encapsulating the TOS as a smart contract and linking it but it makes total sense!

Although for an MVP, would probably be good to just focus on as though the terms are just binary -- user is subscribed, user is unsubscribed.

Agree

Do you feel you'd want to make sure the user signed a transaction associated with the subscription every time a payment was due?

I don't feel like it's better for the consumer in all cases. See the 'opt in ever month' vs 'opt out' models above

Maybe this was already in the plan but yeah it'd be nice ux to have a subscription registry service for all your subscriptions (with updates aggregated in 1 sweep / notification / single monthly or annual transaction by the user then auto-paid to each service).

I agree!

Might be more of a dapp tho like http://scroogeup.com or a budgeting app or advanced wallet but maybe it could be an ERC.

The reason I ERC'd it is that I think this is a core enough piece of infrastructure that it shouldnt be written by a rent seeking ICO or token based model. It should be a core piece of the infrastructure.

For the case of tokens, couldn't you do something similar to 0x,

This is interesting.. Thanks I didnt know about 0x doing this!

The user "approves" the contract for an unlimited allowance

It scares me to have the contract approved for an unlimited allowance. I get that you can mitigate it by code reviewing the smart contract that it's called for the unlimited allowance, but I still think the trust model is funny.

The other thing that

Doing this with ETH is probably harder, as there's nothing like the "approve" function that I'm aware of.

I have heard rumours of ETH being moved to being an ERC20 token, but am unsure of the status there. Does anyone know?

For users to grant price-based withdrawals to a contract, the oracle needs to be able to disable withdrawals during periods of high volatility.

Could you articulate what you mean by 'price based withdrawals'? Do you mean $20 worth of token X every month?

I had not envisioned this protocol being priced based, if thats what you meant. Only use case I had envisioned being in scope was "X tokens per TIME_PERIOD", aka "10 tokens per mont"
.

An important discussion to have is whether this should be baked into Ethereum or whether this should be it's own project built on top of Ethereum.

Yep! My only two core beliefs so far are that I dont want to see a rent seeking token powering this (so thats a vote in favor of being built into Ethereum) and that the system shoudl be trustless (which I think could go eitehr way.)

Personally I believe it's so critical to the development of the dapp ecosystem that a core standard or new functionality that enables this sort of subscription with a consistent method that the user can understand, is warranted.

yes! it fundamentally aligns incentives between user and dapp.

you could envision a model where multiple apps request charges and then a user can approve them at all at once at the end of each month. Apps could decide themselves how long to allow the user to go without approving.

Interesting, I had not though of this. Will noodle on it.

owocki commented Mar 26, 2018

So, to break it down, it seems to me like you could have terms parameters(which could be adjusted potentially with implications on payment), payment calculation, and a signature working together on this.

This is a neat idea.. I hadnt even though of encapsulating the TOS as a smart contract and linking it but it makes total sense!

Although for an MVP, would probably be good to just focus on as though the terms are just binary -- user is subscribed, user is unsubscribed.

Agree

Do you feel you'd want to make sure the user signed a transaction associated with the subscription every time a payment was due?

I don't feel like it's better for the consumer in all cases. See the 'opt in ever month' vs 'opt out' models above

Maybe this was already in the plan but yeah it'd be nice ux to have a subscription registry service for all your subscriptions (with updates aggregated in 1 sweep / notification / single monthly or annual transaction by the user then auto-paid to each service).

I agree!

Might be more of a dapp tho like http://scroogeup.com or a budgeting app or advanced wallet but maybe it could be an ERC.

The reason I ERC'd it is that I think this is a core enough piece of infrastructure that it shouldnt be written by a rent seeking ICO or token based model. It should be a core piece of the infrastructure.

For the case of tokens, couldn't you do something similar to 0x,

This is interesting.. Thanks I didnt know about 0x doing this!

The user "approves" the contract for an unlimited allowance

It scares me to have the contract approved for an unlimited allowance. I get that you can mitigate it by code reviewing the smart contract that it's called for the unlimited allowance, but I still think the trust model is funny.

The other thing that

Doing this with ETH is probably harder, as there's nothing like the "approve" function that I'm aware of.

I have heard rumours of ETH being moved to being an ERC20 token, but am unsure of the status there. Does anyone know?

For users to grant price-based withdrawals to a contract, the oracle needs to be able to disable withdrawals during periods of high volatility.

Could you articulate what you mean by 'price based withdrawals'? Do you mean $20 worth of token X every month?

I had not envisioned this protocol being priced based, if thats what you meant. Only use case I had envisioned being in scope was "X tokens per TIME_PERIOD", aka "10 tokens per mont"
.

An important discussion to have is whether this should be baked into Ethereum or whether this should be it's own project built on top of Ethereum.

Yep! My only two core beliefs so far are that I dont want to see a rent seeking token powering this (so thats a vote in favor of being built into Ethereum) and that the system shoudl be trustless (which I think could go eitehr way.)

Personally I believe it's so critical to the development of the dapp ecosystem that a core standard or new functionality that enables this sort of subscription with a consistent method that the user can understand, is warranted.

yes! it fundamentally aligns incentives between user and dapp.

you could envision a model where multiple apps request charges and then a user can approve them at all at once at the end of each month. Apps could decide themselves how long to allow the user to go without approving.

Interesting, I had not though of this. Will noodle on it.

@marclijour

This comment has been minimized.

Show comment
Hide comment
@marclijour

marclijour Mar 26, 2018

I like the idea and the premises. Industry does have come to like steady cash flow streams vs one-time payments. The second benefit is that such feature will enable businesses processes common to e-commerce and sales. I would argue it is best practice to enforce some ground rules in the lowest protocol where that makes sense vs the dapp layer.

One situation to be avoided is an intermediary could make payment decision on behalf of a customer. The person who is paying should be the one committing the payment directly.

marclijour commented Mar 26, 2018

I like the idea and the premises. Industry does have come to like steady cash flow streams vs one-time payments. The second benefit is that such feature will enable businesses processes common to e-commerce and sales. I would argue it is best practice to enforce some ground rules in the lowest protocol where that makes sense vs the dapp layer.

One situation to be avoided is an intermediary could make payment decision on behalf of a customer. The person who is paying should be the one committing the payment directly.

@ptrwtts

This comment has been minimized.

Show comment
Hide comment
@ptrwtts

ptrwtts Mar 26, 2018

It scares me to have the contract approved for an unlimited allowance

It's true, but unlimited allowances make for a much better UX. That's why with the new #777 standard, unlimited is the only sort of allowance supported (via authorizeOperator). In reality, it's not unlimited, because there are very strict rules coded into the contract about when tokens can be moved. It works best with a shared contract (like 0x), that you only need to audit / approve once, rather than everyone deploying their own.

ptrwtts commented Mar 26, 2018

It scares me to have the contract approved for an unlimited allowance

It's true, but unlimited allowances make for a much better UX. That's why with the new #777 standard, unlimited is the only sort of allowance supported (via authorizeOperator). In reality, it's not unlimited, because there are very strict rules coded into the contract about when tokens can be moved. It works best with a shared contract (like 0x), that you only need to audit / approve once, rather than everyone deploying their own.

@MicahZoltu

This comment has been minimized.

Show comment
Hide comment
@MicahZoltu

MicahZoltu Mar 26, 2018

Contributor

Consider: Pre-paid vs post-paid. Pre-paid puts trust in the service provider, post-paid puts trust in the subscriber. Post-paid allows for things like pro-rated subscriptions on cancellation and some other UX benefits, but subscribers generally can't be trusted compared to service providers (one to many relationships tend to by much more Sybil attackable by the many vs the one).

Contributor

MicahZoltu commented Mar 26, 2018

Consider: Pre-paid vs post-paid. Pre-paid puts trust in the service provider, post-paid puts trust in the subscriber. Post-paid allows for things like pro-rated subscriptions on cancellation and some other UX benefits, but subscribers generally can't be trusted compared to service providers (one to many relationships tend to by much more Sybil attackable by the many vs the one).

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Mar 26, 2018

Consider: Pre-paid vs post-paid

Hi! It's not clear to me what you mean by 'pre paid' vs 'post paid'. Are you using a different verbage vs opt in/opt out verbage that I used in the OP issue desc?

owocki commented Mar 26, 2018

Consider: Pre-paid vs post-paid

Hi! It's not clear to me what you mean by 'pre paid' vs 'post paid'. Are you using a different verbage vs opt in/opt out verbage that I used in the OP issue desc?

@pipermerriam

This comment has been minimized.

Show comment
Hide comment
@pipermerriam

pipermerriam Mar 26, 2018

Member

Here are a few thoughts:

I think that price should be out-of-scope for this standard. This feels a lot like scope creep to me and doesn't need to be part of the core API. Ideally whatever protocol rules are decided allow for this type of behavior.

From the subscriber's side:

  • I want strong guarantees on when I can cancel my subscription.
  • I will normally want payments to happen automatically without any action on my part.
  • In some cases it might be valuable to require an approval process.
  • For dynamically priced subscriptions I want to be able to set limits (require authorization if subscription is more than X).

From the providers's side:

  • I need the ability to charge a fixed fee per subscription time unit (netflix, pandora, etc).
  • I need the ability to charge a dynamic fee per subscription time unit (aws, twilio, etc).
  • I need to be able to create reasonably accurate forecasts for upcoming subscriptions: Programatic checks that subscription accounts have available balance and that subscription is active.

And to think a bit about protocol:

Building on the token ERCs seems valuable here since they already setup primatives for transferring and approving. What's missing is the concept of time based approvals. I think that we can get very close to hitting all of the use cases above with the following API

Subscription API

I think we need the following minimal API

  • triggerPayment() returns bool : Triggers payment of the subscription. This spec does not specify the behavior of this function, leaving it up to the implementer.
  • cancel() returns bool: Immediately cancels the subscription. Implementations should ensure that any unpaid subscription payments are paid to the provider as part of cancellation to ensure providers are able to let subscriptions fees fill up for arbitrary lengths of time, allowing them to reduce overhead from transaction costs.

These probably have Payment and Cancelled events that would get fired.

An ERC20 token based subscription contract.

With the above, we can now think about what a subscription paid in ERC20 tokens might look like. A minimal implementation would require the following fields.

  • address token: defines the token contract which payments are paid from.
  • address provider: the address of the provider
  • uint256 time_unit: the number of seconds per time unit.
  • uint256 tokens_per_time_unit: the number of tokens that can be paid towards the subscription per time_unit.
  • uint256 last_payment_at: the timestamp when the last payment was made.

The triggerPayment method would call token.transfer(provider, (now - last_payment_at) * tokens_per_time_unit / time_unit)`.

Closing Thoughts

Given the wide set of use cases for subscriptions and the wide array of different business requirements, I think this specification will be most useful if it sticks to trying to define an interface, and leaves the exact implementation up to the provider. A provider would either provide their own implementation of a subscription contract, requiring the user to fund the contract once it was created for them, or they might delegate to a 3rd party service which offers pre-built subscription contracts that fit their business requirements.

Member

pipermerriam commented Mar 26, 2018

Here are a few thoughts:

I think that price should be out-of-scope for this standard. This feels a lot like scope creep to me and doesn't need to be part of the core API. Ideally whatever protocol rules are decided allow for this type of behavior.

From the subscriber's side:

  • I want strong guarantees on when I can cancel my subscription.
  • I will normally want payments to happen automatically without any action on my part.
  • In some cases it might be valuable to require an approval process.
  • For dynamically priced subscriptions I want to be able to set limits (require authorization if subscription is more than X).

From the providers's side:

  • I need the ability to charge a fixed fee per subscription time unit (netflix, pandora, etc).
  • I need the ability to charge a dynamic fee per subscription time unit (aws, twilio, etc).
  • I need to be able to create reasonably accurate forecasts for upcoming subscriptions: Programatic checks that subscription accounts have available balance and that subscription is active.

And to think a bit about protocol:

Building on the token ERCs seems valuable here since they already setup primatives for transferring and approving. What's missing is the concept of time based approvals. I think that we can get very close to hitting all of the use cases above with the following API

Subscription API

I think we need the following minimal API

  • triggerPayment() returns bool : Triggers payment of the subscription. This spec does not specify the behavior of this function, leaving it up to the implementer.
  • cancel() returns bool: Immediately cancels the subscription. Implementations should ensure that any unpaid subscription payments are paid to the provider as part of cancellation to ensure providers are able to let subscriptions fees fill up for arbitrary lengths of time, allowing them to reduce overhead from transaction costs.

These probably have Payment and Cancelled events that would get fired.

An ERC20 token based subscription contract.

With the above, we can now think about what a subscription paid in ERC20 tokens might look like. A minimal implementation would require the following fields.

  • address token: defines the token contract which payments are paid from.
  • address provider: the address of the provider
  • uint256 time_unit: the number of seconds per time unit.
  • uint256 tokens_per_time_unit: the number of tokens that can be paid towards the subscription per time_unit.
  • uint256 last_payment_at: the timestamp when the last payment was made.

The triggerPayment method would call token.transfer(provider, (now - last_payment_at) * tokens_per_time_unit / time_unit)`.

Closing Thoughts

Given the wide set of use cases for subscriptions and the wide array of different business requirements, I think this specification will be most useful if it sticks to trying to define an interface, and leaves the exact implementation up to the provider. A provider would either provide their own implementation of a subscription contract, requiring the user to fund the contract once it was created for them, or they might delegate to a 3rd party service which offers pre-built subscription contracts that fit their business requirements.

@niran

This comment has been minimized.

Show comment
Hide comment
@niran

niran Mar 27, 2018

I think most tokens are too volatile for people to be comfortable denominating subscriptions in, (e.g. all crypto subscriptions would've been cancelled last fall) but let's find out

niran commented Mar 27, 2018

I think most tokens are too volatile for people to be comfortable denominating subscriptions in, (e.g. all crypto subscriptions would've been cancelled last fall) but let's find out

@abunsen

This comment has been minimized.

Show comment
Hide comment
@abunsen

abunsen Mar 28, 2018

Hi! It's not clear to me what you mean by 'pre paid' vs 'post paid'. Are you using a different verbage vs opt in/opt out verbage that I used in the OP issue desc?

I'm not speaking on his behalf, but my read on it was that pre-paid means paying upfront for service and post-paid at the end of the period. Like how you have to pay your rent up front, but you pay your Netflix subscription at the end of the month. It's independent of opt-in/opt-out.

Until (and if) ETH becomes a token, it would not be viable to do this at all with ETH.

Excuse my ignorance, but why is this not viable to do with ETH?


I love this proposal & have been thinking about it for a few months. It could really put the power in the hands of the consumer / customer - right now if I want to cancel my Netflix, I have to log in to my Netflix account or worse (e.g. get on the phone 😲 ). Rinse and repeat for any other poor choices I've made with my credit card info (e.g. my Knit-Wise.com subscription or my XtremeNitroShred.com subscription).

The way I've been thinking about this is as follows (keep in mind, I'm an ETH hobbyist, not a professional solidity dev):

  1. Subscriber creates a single "subscriptions contract" that will manage their subscriptions
  2. Subscriber funds that contract
  3. The subscriptions contract manages subscriptions by having something like an array of "approved subscription" structs (name, web domain, ETH address, amount, interval)
  4. External "vendor contracts" can make a request to become a vendor in the "approved subscription" array
  5. Vendor contracts that are in the "approved subscription" array can make calls to withdraw based on the previously agreed upon amount and interval
  6. A user can cancel a subscription at any time by removing the vendor from the array
  7. Subscriber should be able to destroy entire subscriptions contract and have remaining ETH sent back to their address

The assumptions this is based on:

  • Priced in ETH, not USD (so no need for Oracles)
  • The subscriptions are based on paying up-front like the pricing presented on https://quiknode.io/

Some things I thought might be worth considering:

  • How can I verify that I'm actually getting a request from Netflix? This might be as simple as having netflix.com host a netflix.com/subscriptions.eth file with their approved vendor contract addresses
  • How could we update the code? Well since each user is deploying one of these contracts on an as needed basis, we could have versions & make improvements to the standard.
  • How private should this be? I think to start, not that private. We can iterate on standard (see line above) & add in these features as people build a desire to maintain privacy.

abunsen commented Mar 28, 2018

Hi! It's not clear to me what you mean by 'pre paid' vs 'post paid'. Are you using a different verbage vs opt in/opt out verbage that I used in the OP issue desc?

I'm not speaking on his behalf, but my read on it was that pre-paid means paying upfront for service and post-paid at the end of the period. Like how you have to pay your rent up front, but you pay your Netflix subscription at the end of the month. It's independent of opt-in/opt-out.

Until (and if) ETH becomes a token, it would not be viable to do this at all with ETH.

Excuse my ignorance, but why is this not viable to do with ETH?


I love this proposal & have been thinking about it for a few months. It could really put the power in the hands of the consumer / customer - right now if I want to cancel my Netflix, I have to log in to my Netflix account or worse (e.g. get on the phone 😲 ). Rinse and repeat for any other poor choices I've made with my credit card info (e.g. my Knit-Wise.com subscription or my XtremeNitroShred.com subscription).

The way I've been thinking about this is as follows (keep in mind, I'm an ETH hobbyist, not a professional solidity dev):

  1. Subscriber creates a single "subscriptions contract" that will manage their subscriptions
  2. Subscriber funds that contract
  3. The subscriptions contract manages subscriptions by having something like an array of "approved subscription" structs (name, web domain, ETH address, amount, interval)
  4. External "vendor contracts" can make a request to become a vendor in the "approved subscription" array
  5. Vendor contracts that are in the "approved subscription" array can make calls to withdraw based on the previously agreed upon amount and interval
  6. A user can cancel a subscription at any time by removing the vendor from the array
  7. Subscriber should be able to destroy entire subscriptions contract and have remaining ETH sent back to their address

The assumptions this is based on:

  • Priced in ETH, not USD (so no need for Oracles)
  • The subscriptions are based on paying up-front like the pricing presented on https://quiknode.io/

Some things I thought might be worth considering:

  • How can I verify that I'm actually getting a request from Netflix? This might be as simple as having netflix.com host a netflix.com/subscriptions.eth file with their approved vendor contract addresses
  • How could we update the code? Well since each user is deploying one of these contracts on an as needed basis, we could have versions & make improvements to the standard.
  • How private should this be? I think to start, not that private. We can iterate on standard (see line above) & add in these features as people build a desire to maintain privacy.
@pipermerriam

This comment has been minimized.

Show comment
Hide comment
@pipermerriam

pipermerriam Mar 28, 2018

Member

I think most tokens are too volatile for people to be comfortable denominating subscriptions in

one particular token comes to mind which may prove to be an illustrative counter-example. Even if most are not suitable for this, it only takes a few that are stable and fungible to make it worthwhile. (my 2 cents)

Member

pipermerriam commented Mar 28, 2018

I think most tokens are too volatile for people to be comfortable denominating subscriptions in

one particular token comes to mind which may prove to be an illustrative counter-example. Even if most are not suitable for this, it only takes a few that are stable and fungible to make it worthwhile. (my 2 cents)

@nieldlr

This comment has been minimized.

Show comment
Hide comment
@nieldlr

nieldlr Mar 28, 2018

Heya everyone,

dig this discussion a lot @owocki! Thanks for kicking this off.

I'm the creator of StakeTree a crypto equivalent of Patreon. It's still early days, but I've got some pilot projects running to test market interest and there seems to be quite a neat demand for this. (I'm even funding myself through this!). I've thought a bit on this and tried some contract variants on how to make some kind of pseudo-subscription system. I'm a new solidity dev so there's still lots that I might miss here.

To @owocki's point, on the merit of a subscription standard, I'm fully onboard with this. Having previously worked in SaaS, it's a massive industry and having subscriptions could be hugely beneficial for crypto projects.

My naive implementation to get this working was to have a contract where funders can pool money into the contract and the beneficiary can then withdraw 10% from the pool every week. Funders can refund whatever is left of their funds at any time. For example, if they put in 1 eth, and two withdrawals have occurred, they can then refund themselves 0.81 eth if they want to or continue funding the beneficiary.

See code here.

There's an additional tokenization aspect I added which is unrelated to this discussion (it allows you to reward funders for their contribution).

This implementation is sub-optimal in my view because it requires a big capital upfront cost for the subscription. 1 eth only generates 0.1 eth of "payment", then diminishes every week by 10%. Although this could be useful for a Patreon-style subscription where the exact funds aren't the issue, but rather that funds are there. In cases where an exact payment amount is needed, this doesn't work.

I then tried to do a cleaner version where you could commit to X amount of ether over Y weeks. I called it X-Over-Y subscriptions. So let's say I want to use Netflix for 12 weeks, I can pay upfront and then the beneficiary can withdraw the allocated funds each week. However, I ran into gas cost issues very quickly due to iteration. In most cases, this was my concern technically with subscriptions on smart contracts. I was working on these before CryptoKitties arrived and then it was just barely plausible for gas costs, but soon, the network congested and it became incredibly unfeasible. (To reiterate, I'm not the best solidity dev here, so I might have missed something).

I might be reading these wrong (please do correct me!), but it seems like @pipermerriam, @ptrwtts & @abunsen's possible implementations would require the provider/beneficiary (the project/person receiving the funds) to send a transaction for each subscriber. This kind of scalability might be solved in future, but at the moment, this has been a big blocker for me because of inherent costs and potential uncertainty regarding fluctuating gas price. This is also a tricky UX issue. If the provider runs a withdraw action on a front-end and triggers multiple transactions, what's the easiest way to have that run without someone sitting there signing each transaction?

The other kind of scalability that iterates within a contract, let's say, all there's some kind of aggregation where all subscribers gather in one contract for the provider/beneficiary, could lead to gas limit issues. I solved this by using some math to calculate the totals for funders on the fly and only store how many withdrawals occurred and at what withdrawal they started their funding. But this might lead to the 10% issue, where all funders would have the pay the same amount. (I might look into this again in the future).

At the risk of not letting this get too technical & sorry for being a bit late to this discussion. I'm in agreement that a common interface would be really amazing here, but the reason I go a bit deeper here is so that I can urge proposers to please consider the usability & scalability of a subscriptions standard as well. When proposals are put forth, can we also discuss scenarios of how it would work for 1 subscriber, 10 subscribers, 500 subscribers, 1000 subscribers etc. If it doesn't scale, any subscription can be trivially DOSd. Never mind the possibility of a sybil attack added on top of this.

I'm hugely excited for this. I'd love to hear more thoughts here. And again sorry if I misunderstood some of the suggested implementations (y'all are all probably much smarter than me!). If either we create a scalable subscriptions standard on the smart contract level or we look at the core ethereum level, this will be huge. Thanks again @owocki! Let's do this!

nieldlr commented Mar 28, 2018

Heya everyone,

dig this discussion a lot @owocki! Thanks for kicking this off.

I'm the creator of StakeTree a crypto equivalent of Patreon. It's still early days, but I've got some pilot projects running to test market interest and there seems to be quite a neat demand for this. (I'm even funding myself through this!). I've thought a bit on this and tried some contract variants on how to make some kind of pseudo-subscription system. I'm a new solidity dev so there's still lots that I might miss here.

To @owocki's point, on the merit of a subscription standard, I'm fully onboard with this. Having previously worked in SaaS, it's a massive industry and having subscriptions could be hugely beneficial for crypto projects.

My naive implementation to get this working was to have a contract where funders can pool money into the contract and the beneficiary can then withdraw 10% from the pool every week. Funders can refund whatever is left of their funds at any time. For example, if they put in 1 eth, and two withdrawals have occurred, they can then refund themselves 0.81 eth if they want to or continue funding the beneficiary.

See code here.

There's an additional tokenization aspect I added which is unrelated to this discussion (it allows you to reward funders for their contribution).

This implementation is sub-optimal in my view because it requires a big capital upfront cost for the subscription. 1 eth only generates 0.1 eth of "payment", then diminishes every week by 10%. Although this could be useful for a Patreon-style subscription where the exact funds aren't the issue, but rather that funds are there. In cases where an exact payment amount is needed, this doesn't work.

I then tried to do a cleaner version where you could commit to X amount of ether over Y weeks. I called it X-Over-Y subscriptions. So let's say I want to use Netflix for 12 weeks, I can pay upfront and then the beneficiary can withdraw the allocated funds each week. However, I ran into gas cost issues very quickly due to iteration. In most cases, this was my concern technically with subscriptions on smart contracts. I was working on these before CryptoKitties arrived and then it was just barely plausible for gas costs, but soon, the network congested and it became incredibly unfeasible. (To reiterate, I'm not the best solidity dev here, so I might have missed something).

I might be reading these wrong (please do correct me!), but it seems like @pipermerriam, @ptrwtts & @abunsen's possible implementations would require the provider/beneficiary (the project/person receiving the funds) to send a transaction for each subscriber. This kind of scalability might be solved in future, but at the moment, this has been a big blocker for me because of inherent costs and potential uncertainty regarding fluctuating gas price. This is also a tricky UX issue. If the provider runs a withdraw action on a front-end and triggers multiple transactions, what's the easiest way to have that run without someone sitting there signing each transaction?

The other kind of scalability that iterates within a contract, let's say, all there's some kind of aggregation where all subscribers gather in one contract for the provider/beneficiary, could lead to gas limit issues. I solved this by using some math to calculate the totals for funders on the fly and only store how many withdrawals occurred and at what withdrawal they started their funding. But this might lead to the 10% issue, where all funders would have the pay the same amount. (I might look into this again in the future).

At the risk of not letting this get too technical & sorry for being a bit late to this discussion. I'm in agreement that a common interface would be really amazing here, but the reason I go a bit deeper here is so that I can urge proposers to please consider the usability & scalability of a subscriptions standard as well. When proposals are put forth, can we also discuss scenarios of how it would work for 1 subscriber, 10 subscribers, 500 subscribers, 1000 subscribers etc. If it doesn't scale, any subscription can be trivially DOSd. Never mind the possibility of a sybil attack added on top of this.

I'm hugely excited for this. I'd love to hear more thoughts here. And again sorry if I misunderstood some of the suggested implementations (y'all are all probably much smarter than me!). If either we create a scalable subscriptions standard on the smart contract level or we look at the core ethereum level, this will be huge. Thanks again @owocki! Let's do this!

@Josephrp

This comment has been minimized.

Show comment
Hide comment
@Josephrp

Josephrp Mar 28, 2018

I'm not sure I'm fully convinced by the rational for the EIP. In fiat country subscription services are in fact highly regulated via amongst other things something called a "clearing house". It might be the case that a service provider eg "ClearETH" could be the intermediary between users and their subscription providers and solve much of this while not reducing a user's control.

Josephrp commented Mar 28, 2018

I'm not sure I'm fully convinced by the rational for the EIP. In fiat country subscription services are in fact highly regulated via amongst other things something called a "clearing house". It might be the case that a service provider eg "ClearETH" could be the intermediary between users and their subscription providers and solve much of this while not reducing a user's control.

@charlieknoll

This comment has been minimized.

Show comment
Hide comment
@charlieknoll

charlieknoll Mar 28, 2018

Regarding @pipermerriam's spec, it should be required that the cancel function should trigger unpaid payment. This way payments can be accumulated and the provider only needs to call the triggerPayment function when they need access to their accumulated Dai. This will help with scalability such that the provider can time their payments to times of low network usage and gas prices.

charlieknoll commented Mar 28, 2018

Regarding @pipermerriam's spec, it should be required that the cancel function should trigger unpaid payment. This way payments can be accumulated and the provider only needs to call the triggerPayment function when they need access to their accumulated Dai. This will help with scalability such that the provider can time their payments to times of low network usage and gas prices.

@pipermerriam

This comment has been minimized.

Show comment
Hide comment
@pipermerriam

pipermerriam Mar 29, 2018

Member

Regarding @pipermerriam's spec, it should be required that the cancel function should trigger unpaid payment.

I've updated my post to include this. Note that my spec makes no requirements on what the underlying implementation does in terms of functionality, so this was added as a "should" to ensure that implementers are aware of this use case.

Member

pipermerriam commented Mar 29, 2018

Regarding @pipermerriam's spec, it should be required that the cancel function should trigger unpaid payment.

I've updated my post to include this. Note that my spec makes no requirements on what the underlying implementation does in terms of functionality, so this was added as a "should" to ensure that implementers are aware of this use case.

@pipermerriam

This comment has been minimized.

Show comment
Hide comment
@pipermerriam

pipermerriam Mar 29, 2018

Member

@nieldlr I think I understand your concerns, however, from the complexity/security/optimization/efficiency trade-off perspective, I think that a contract-per-subscription is the right choice.

Providers can still batch their withdrawals which should have a noticeable effect on reducing transaction overhead. In theory calls to the triggerPayment should be able to be optimized to be well within a 100k gas budget which puts it close enough to the fully optimized threshold that to achieve any more significant gains will require protocol level scalability.

Member

pipermerriam commented Mar 29, 2018

@nieldlr I think I understand your concerns, however, from the complexity/security/optimization/efficiency trade-off perspective, I think that a contract-per-subscription is the right choice.

Providers can still batch their withdrawals which should have a noticeable effect on reducing transaction overhead. In theory calls to the triggerPayment should be able to be optimized to be well within a 100k gas budget which puts it close enough to the fully optimized threshold that to achieve any more significant gains will require protocol level scalability.

@ptrwtts

This comment has been minimized.

Show comment
Hide comment
@ptrwtts

ptrwtts Mar 29, 2018

@pipermerriam wouldn't a single shared contract be better than a contract per subscription? this way, you can have confidence around what it will do, without having to audit every single subscription you do. i'm guessing it would also be cheaper to setup, if you used a createSubscription() function instead of deploying a contract every time.

it could either be one universal contract, or at least one contract per service (similar to tokens).

ptrwtts commented Mar 29, 2018

@pipermerriam wouldn't a single shared contract be better than a contract per subscription? this way, you can have confidence around what it will do, without having to audit every single subscription you do. i'm guessing it would also be cheaper to setup, if you used a createSubscription() function instead of deploying a contract every time.

it could either be one universal contract, or at least one contract per service (similar to tokens).

@pipermerriam

This comment has been minimized.

Show comment
Hide comment
@pipermerriam

pipermerriam Mar 29, 2018

Member

@ptrwtts My preference for a contract-per-subscription model is fueled by the same reason that ENS uses stand-alone deed contracts. Since these contracts hold user funds, by keeping them in separate contracts you reduce the attack surface area by eliminating an entire class of attack since user's funds are not intermingled.

Member

pipermerriam commented Mar 29, 2018

@ptrwtts My preference for a contract-per-subscription model is fueled by the same reason that ENS uses stand-alone deed contracts. Since these contracts hold user funds, by keeping them in separate contracts you reduce the attack surface area by eliminating an entire class of attack since user's funds are not intermingled.

@cryppadotta

This comment has been minimized.

Show comment
Hide comment
@cryppadotta

cryppadotta Apr 2, 2018

I've implemented pre-paid "subscriptions" in dotta-license by setting an expiration time on an ERC721 token.

At checkout, users select the length of time they want to pre-pay:

screenshot 2018-04-02 09 44 20

When the token is issued, it sets an expiration according the number of "cycles" the user paid for. Users can renew at any time.

My client-side app verifies that the token has not expired. (You could do this with a desktop app, mobile, or SaaS service.) Because the verification is client-side you can provide any sort of "grace" period you want, such as not disabling until it's been unpaid for a certain amount of time.

Also, because there is a client-side app, I'm using that app for reminders when the subscription is near-due.

From a sellers perspective, credit-card based subscriptions are be beneficial in that users are default-pay (for example, if they forget or just do nothing, you still retain the subscriber). Obviously, we don't have that in Ethereum today.

For pricing, there is code that will sync a list of products and their prices. I update prices periodically to be reasonable within conversion rates.

However, the downside(?) to this (optional) process is that a subscription's price isn't "fixed" (or grandfathered) to a particular price in ETH. I tell my customers that it they want a fixed rate, then they ought to pre-pay for a longer time period. There are interesting incentive dynamics here.

The code is all open-source/MIT, including the contracts, commandline management tools, and React UI widget.

cryppadotta commented Apr 2, 2018

I've implemented pre-paid "subscriptions" in dotta-license by setting an expiration time on an ERC721 token.

At checkout, users select the length of time they want to pre-pay:

screenshot 2018-04-02 09 44 20

When the token is issued, it sets an expiration according the number of "cycles" the user paid for. Users can renew at any time.

My client-side app verifies that the token has not expired. (You could do this with a desktop app, mobile, or SaaS service.) Because the verification is client-side you can provide any sort of "grace" period you want, such as not disabling until it's been unpaid for a certain amount of time.

Also, because there is a client-side app, I'm using that app for reminders when the subscription is near-due.

From a sellers perspective, credit-card based subscriptions are be beneficial in that users are default-pay (for example, if they forget or just do nothing, you still retain the subscriber). Obviously, we don't have that in Ethereum today.

For pricing, there is code that will sync a list of products and their prices. I update prices periodically to be reasonable within conversion rates.

However, the downside(?) to this (optional) process is that a subscription's price isn't "fixed" (or grandfathered) to a particular price in ETH. I tell my customers that it they want a fixed rate, then they ought to pre-pay for a longer time period. There are interesting incentive dynamics here.

The code is all open-source/MIT, including the contracts, commandline management tools, and React UI widget.

@tjayrush

This comment has been minimized.

Show comment
Hide comment
@tjayrush

tjayrush Apr 3, 2018

@cryppadotta

However, the downside(?) to this (optional) process is that a subscription's price isn't "fixed" (or grandfathered) to a particular price in ETH

I actually see this as a benefit. If you build in a short waiting period during which time your client could either quit your service (because the price you set is too high) or make a counter-offer (because he/she believes the exchange rate is not fair), then you actually have a model that might work. As it is, I don't like that only you can change the rate.

tjayrush commented Apr 3, 2018

@cryppadotta

However, the downside(?) to this (optional) process is that a subscription's price isn't "fixed" (or grandfathered) to a particular price in ETH

I actually see this as a benefit. If you build in a short waiting period during which time your client could either quit your service (because the price you set is too high) or make a counter-offer (because he/she believes the exchange rate is not fair), then you actually have a model that might work. As it is, I don't like that only you can change the rate.

@pipermerriam

This comment has been minimized.

Show comment
Hide comment
@pipermerriam

pipermerriam Apr 3, 2018

Member

@tjayrush / @cryppadotta

I believe the schemes your both mentioning can be accomplished under the spec I proposed here. Please correct me if I'm wrong.

Member

pipermerriam commented Apr 3, 2018

@tjayrush / @cryppadotta

I believe the schemes your both mentioning can be accomplished under the spec I proposed here. Please correct me if I'm wrong.

@nieldlr

This comment has been minimized.

Show comment
Hide comment
@nieldlr

nieldlr Apr 4, 2018

@nieldlr I think I understand your concerns, however, from the complexity/security/optimization/efficiency trade-off perspective, I think that a contract-per-subscription is the right choice.

Providers can still batch their withdrawals which should have a noticeable effect on reducing transaction overhead. In theory calls to the triggerPayment should be able to be optimized to be well within a 100k gas budget which puts it close enough to the fully optimized threshold that to achieve any more significant gains will require protocol level scalability.

Heya @pipermerriam, could you explain a bit more on how this works? I'm not quite familiar with batching and how this exactly works here. Eager to learn if this could solve our challenge.

Again, from a purely practical point of view, having multiple tx costs to the provider is not scalable. My focus is primarily on people building up support from their communities/fans/supporters and this type of funding can be much smaller. Here's the income distribution on Patreon for example:
image

My withdraw function is currently sitting about ~50k gas cost & back during the network spike in December/January I ended up paying $0.50 per withdrawal. https://etherscan.io/tx/0xe6e5534baee4a6d91c2d288dfb803199d0e1dcb8c3798162dc2a4bb11935a8df

Back then I had about 20 funders, which means that if I ran a ~100k gas cost withdrawal for all of them, it would've cost me $1*20 = $20. This is unfortunately not a reasonable cost for a provider & I would call that a failure of Ethereum to be able to handle subscriptions and rather prefer using centralized providers like Patreon. I'm taking the extreme case here in terms of network congestion, but this is by far not the most extreme in terms of how many funders one could get for a project/app etc. It's just not a user experience risk that I'm comfortable with taking for an app/service

I'm fully aware that we might need to make some tradeoffs here somewhere, but my hunch is that perhaps there's a different way to solve this. Eager to hear if batching (or any other solution) might solve this.

Thanks for exploring this with me (and everyone else here!). I'm passionate about this, because I believe this opens up so many opportunities.

nieldlr commented Apr 4, 2018

@nieldlr I think I understand your concerns, however, from the complexity/security/optimization/efficiency trade-off perspective, I think that a contract-per-subscription is the right choice.

Providers can still batch their withdrawals which should have a noticeable effect on reducing transaction overhead. In theory calls to the triggerPayment should be able to be optimized to be well within a 100k gas budget which puts it close enough to the fully optimized threshold that to achieve any more significant gains will require protocol level scalability.

Heya @pipermerriam, could you explain a bit more on how this works? I'm not quite familiar with batching and how this exactly works here. Eager to learn if this could solve our challenge.

Again, from a purely practical point of view, having multiple tx costs to the provider is not scalable. My focus is primarily on people building up support from their communities/fans/supporters and this type of funding can be much smaller. Here's the income distribution on Patreon for example:
image

My withdraw function is currently sitting about ~50k gas cost & back during the network spike in December/January I ended up paying $0.50 per withdrawal. https://etherscan.io/tx/0xe6e5534baee4a6d91c2d288dfb803199d0e1dcb8c3798162dc2a4bb11935a8df

Back then I had about 20 funders, which means that if I ran a ~100k gas cost withdrawal for all of them, it would've cost me $1*20 = $20. This is unfortunately not a reasonable cost for a provider & I would call that a failure of Ethereum to be able to handle subscriptions and rather prefer using centralized providers like Patreon. I'm taking the extreme case here in terms of network congestion, but this is by far not the most extreme in terms of how many funders one could get for a project/app etc. It's just not a user experience risk that I'm comfortable with taking for an app/service

I'm fully aware that we might need to make some tradeoffs here somewhere, but my hunch is that perhaps there's a different way to solve this. Eager to hear if batching (or any other solution) might solve this.

Thanks for exploring this with me (and everyone else here!). I'm passionate about this, because I believe this opens up so many opportunities.

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Apr 4, 2018

I wonder if the optimal interface for 1:many subscriptions (neil's point above) is different than the optimal interface for1:1 subscription contract (piper's interface).

there is certainly a tradeoff from an attack surface perspective, as it's a nice best practice from a security perspective to be able to keep funds for different subscriptions in seperate contracts to make each contract less of a honeypot

owocki commented Apr 4, 2018

I wonder if the optimal interface for 1:many subscriptions (neil's point above) is different than the optimal interface for1:1 subscription contract (piper's interface).

there is certainly a tradeoff from an attack surface perspective, as it's a nice best practice from a security perspective to be able to keep funds for different subscriptions in seperate contracts to make each contract less of a honeypot

@pipermerriam

This comment has been minimized.

Show comment
Hide comment
@pipermerriam

pipermerriam Apr 4, 2018

Member

Heya @pipermerriam, could you explain a bit more on how this works? I'm not quite familiar with batching and how this exactly works here. Eager to learn if this could solve our challenge.

Each user would have their own subscription contract. The naive approach would be to send 1 transaction for each subscriber, calling triggerPayment on each subscription contract.

To batch these, you would do this with another contract layer. Here's a psuedo-solidity implementation.

contract SubscriptionInterface {
  function triggerPayment() returns (bool);
}
contract BatchTriggerPayment {
  function triggerBatchPayments(address[] subscriptions) returns (bool success) {
    for (uint i=0; i<subscriptions.length; i++) {
        success = SubscriptionInterface(subscriptions[i]).triggerPayment();
        if (!success) {
          revert();
        }
    }
  }
}

This should save you 21000 gas of overhead for each subscription, reducing the gas footprint to the overhead of a single transaction + the cost of triggering a payment for each subscription.

It's still an O(n) cost, but it's reduced by an O(n) factor due to the savings on transaction overhead.

Remember that true scalability is something that will happen at the protocol level, after which most of this gas accounting and optimization should matter way less.

Member

pipermerriam commented Apr 4, 2018

Heya @pipermerriam, could you explain a bit more on how this works? I'm not quite familiar with batching and how this exactly works here. Eager to learn if this could solve our challenge.

Each user would have their own subscription contract. The naive approach would be to send 1 transaction for each subscriber, calling triggerPayment on each subscription contract.

To batch these, you would do this with another contract layer. Here's a psuedo-solidity implementation.

contract SubscriptionInterface {
  function triggerPayment() returns (bool);
}
contract BatchTriggerPayment {
  function triggerBatchPayments(address[] subscriptions) returns (bool success) {
    for (uint i=0; i<subscriptions.length; i++) {
        success = SubscriptionInterface(subscriptions[i]).triggerPayment();
        if (!success) {
          revert();
        }
    }
  }
}

This should save you 21000 gas of overhead for each subscription, reducing the gas footprint to the overhead of a single transaction + the cost of triggering a payment for each subscription.

It's still an O(n) cost, but it's reduced by an O(n) factor due to the savings on transaction overhead.

Remember that true scalability is something that will happen at the protocol level, after which most of this gas accounting and optimization should matter way less.

@alexvandesande

This comment has been minimized.

Show comment
Hide comment
@alexvandesande

alexvandesande Apr 6, 2018

Contributor

Can't this be done by signing some time-locked erc20 cheques somehow? Ideally the user should sign a message saying "after block X, transfer N tokens to Bob". They could do it 12 times for all months and renew the subscription next month. The scope and how to do time lock cheques is what should be is debate in this ERC.

Contributor

alexvandesande commented Apr 6, 2018

Can't this be done by signing some time-locked erc20 cheques somehow? Ideally the user should sign a message saying "after block X, transfer N tokens to Bob". They could do it 12 times for all months and renew the subscription next month. The scope and how to do time lock cheques is what should be is debate in this ERC.

@leafcutterant

This comment has been minimized.

Show comment
Hide comment
@leafcutterant

leafcutterant Apr 6, 2018

Until (and if) ETH becomes a token, it would not be viable to do this at all with ETH.

Through WETH, ETH already is (can be) a token. I'm not familiar with the WETH contract, but maybe the conversion can be automated by the subscription contract(s).

Side note: I think subscriptions can benefit greatly from a stablecoin like Dai. Most people probably won't want to commit to a subscription or get payments in a currency which they don't know the future value of.

leafcutterant commented Apr 6, 2018

Until (and if) ETH becomes a token, it would not be viable to do this at all with ETH.

Through WETH, ETH already is (can be) a token. I'm not familiar with the WETH contract, but maybe the conversion can be automated by the subscription contract(s).

Side note: I think subscriptions can benefit greatly from a stablecoin like Dai. Most people probably won't want to commit to a subscription or get payments in a currency which they don't know the future value of.

@gtaschuk

This comment has been minimized.

Show comment
Hide comment
@gtaschuk

gtaschuk Apr 6, 2018

My team took a look into ethereum recurring subscriptions at a Consensys Academy hackathon. The method we opted for was a pre-paid subscription with ethereum held in escrow.

The service provider can at any point withdraw from escrow the (rate of subscription)*(time since the subscription started).

The customer can at any point, add money to escrow (to buy them more time) or cancel their subscription and withdraw any unused funds from escrow.

In this way, subscriptions can be cancelled at any time, and are paid at a continuous rate (effectively allowed pro-rated monthly subscriptions.)

We also took it a bit further and allowed users to "lock in" a lower rate by paying ahead and commiting to a longer subscription. There's still a lot of work to make it a fully functioning dApp, but what we liked about the "pay as you go" and "lock-in" options is that service providers can incentivize loyalty for their users by parameterizing the agreement for "lock-in" (ameliorating the escrow necessity), and you could potentially support multiple subscriptions with one escrow.

Repo with contracts
Slides

gtaschuk commented Apr 6, 2018

My team took a look into ethereum recurring subscriptions at a Consensys Academy hackathon. The method we opted for was a pre-paid subscription with ethereum held in escrow.

The service provider can at any point withdraw from escrow the (rate of subscription)*(time since the subscription started).

The customer can at any point, add money to escrow (to buy them more time) or cancel their subscription and withdraw any unused funds from escrow.

In this way, subscriptions can be cancelled at any time, and are paid at a continuous rate (effectively allowed pro-rated monthly subscriptions.)

We also took it a bit further and allowed users to "lock in" a lower rate by paying ahead and commiting to a longer subscription. There's still a lot of work to make it a fully functioning dApp, but what we liked about the "pay as you go" and "lock-in" options is that service providers can incentivize loyalty for their users by parameterizing the agreement for "lock-in" (ameliorating the escrow necessity), and you could potentially support multiple subscriptions with one escrow.

Repo with contracts
Slides

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Apr 6, 2018

My team took a look into ethereum recurring subscriptions at a Consensys Academy hackathon. The method we opted for was a pre-paid subscription with ethereum held in escrow.

While I respect your prior art in the space (and commend you for taking a stab).. My view is that pre-paying subscriptions is not an optimal UX for an end user. By placing the money for a 12 month subscription in escrow, the user effectively loses the means to use that capital for other things. Problem gets worse when you start talking about 24 month, 36 month, potentially even longer subscriptions.

Side note: I think subscriptions can benefit greatly from a stablecoin like Dai. Most people probably won't want to commit to a subscription or get payments in a currency which they don't know the future value of.

Strongly agree.

owocki commented Apr 6, 2018

My team took a look into ethereum recurring subscriptions at a Consensys Academy hackathon. The method we opted for was a pre-paid subscription with ethereum held in escrow.

While I respect your prior art in the space (and commend you for taking a stab).. My view is that pre-paying subscriptions is not an optimal UX for an end user. By placing the money for a 12 month subscription in escrow, the user effectively loses the means to use that capital for other things. Problem gets worse when you start talking about 24 month, 36 month, potentially even longer subscriptions.

Side note: I think subscriptions can benefit greatly from a stablecoin like Dai. Most people probably won't want to commit to a subscription or get payments in a currency which they don't know the future value of.

Strongly agree.

@evbots

This comment has been minimized.

Show comment
Hide comment
@evbots

evbots Apr 7, 2018

This was an insightful thread to read through. Thanks @owocki for opening this issue. As I understand it, with 0x contracts the user initiates an allowance on their token balance, then subsequently creates or fills an order leveraging that allowance. The allowance doesn't have to be unlimited, but it is more gas efficient.

As @gtaschuk mentioned an alternative to allowances is to use an escrow contract. Very cool what he's done and I'm starting to look over that code. I think the ideal solution for the simple subscription scenario wouldn't require moving funds into a separate contract. I'm not sure what the mechanics would look like exactly, but the main benefit I see of a UX similar to 0x is that the user wouldn't have to first transfer Ether (or wrapped ether WETH) back into their account in order to spend it elsewhere.

evbots commented Apr 7, 2018

This was an insightful thread to read through. Thanks @owocki for opening this issue. As I understand it, with 0x contracts the user initiates an allowance on their token balance, then subsequently creates or fills an order leveraging that allowance. The allowance doesn't have to be unlimited, but it is more gas efficient.

As @gtaschuk mentioned an alternative to allowances is to use an escrow contract. Very cool what he's done and I'm starting to look over that code. I think the ideal solution for the simple subscription scenario wouldn't require moving funds into a separate contract. I'm not sure what the mechanics would look like exactly, but the main benefit I see of a UX similar to 0x is that the user wouldn't have to first transfer Ether (or wrapped ether WETH) back into their account in order to spend it elsewhere.

@dpyro

This comment has been minimized.

Show comment
Hide comment
@dpyro

dpyro Apr 8, 2018

Lot of exciting ideas here! I think a common subscription interface would be incredibly powerful for the Ethereum ecosystem for both users and providers and would spurn further innovation--much like ERC-20 has already done. Here are some thoughts:

The subscription period should be widely variable and not focused around a 30 day timeframe. The minimum subscription period is likely 1 block. Add in a micropayments channel and you can charge users in up to ~15second intervals. Think of Amazon Web Services, for example, where you can elect to subscribe by the minute.

The provider should deploy a subscription contract. They have the greatest need to tailor payment schedules according to the services. The user could optionally use a contract to manage their subscriptions. For example, they could prioritize certain services over others.

A zero payment should be valid. One use case is a notification subscription.

Payments may be flexible. A subscriber should be able to propose both a payment and a time period. This should be submitted through a payment proposal verification contract that may or may not be part of the rest of the subscription contract which enables third party hooks. This contract should either approve or reject the payment in its entirety. Only the final, accepted payment should be recorded in the blockchain. This is similar to how 0x relay providers work. Each may provide its own fee schedule and can either accept or reject an off-chain into its orderbook based on the fee parameters proposed by the order maker.

Payment should support at least ERC #20 and ERC #721 but perhaps any proposed transaction. The most generic method I can think of is to allow the subscriber to propose the payment as a list of at least 0 arbitrary transactions, all of which must be invoked together. As an example, the subscriber could propose to transfer a certain amount of a certain token in one transaction signed by their key and increment the subscription expiration date associated to them in the next transaction which will be signed by the provider in the proposed link. (I believe payment channels get the procedure of this correct.) The acceptable transactions would almost certainly be highly constrained to whitelisted contracts and methods to prevent arbitrary contract execution and exploits.

Depending on the service provided, its very likely there will be no way to verify a provider rendered the subscribed services without using an oracle. What is verifiable is the existence of a payment to that provider. For this reason, a prepay model of crediting is the pragmatic choice.

I'm fairly new to this but I do think we should try to think beyond what we are used to and instead try what is both pragmatic and possible.

dpyro commented Apr 8, 2018

Lot of exciting ideas here! I think a common subscription interface would be incredibly powerful for the Ethereum ecosystem for both users and providers and would spurn further innovation--much like ERC-20 has already done. Here are some thoughts:

The subscription period should be widely variable and not focused around a 30 day timeframe. The minimum subscription period is likely 1 block. Add in a micropayments channel and you can charge users in up to ~15second intervals. Think of Amazon Web Services, for example, where you can elect to subscribe by the minute.

The provider should deploy a subscription contract. They have the greatest need to tailor payment schedules according to the services. The user could optionally use a contract to manage their subscriptions. For example, they could prioritize certain services over others.

A zero payment should be valid. One use case is a notification subscription.

Payments may be flexible. A subscriber should be able to propose both a payment and a time period. This should be submitted through a payment proposal verification contract that may or may not be part of the rest of the subscription contract which enables third party hooks. This contract should either approve or reject the payment in its entirety. Only the final, accepted payment should be recorded in the blockchain. This is similar to how 0x relay providers work. Each may provide its own fee schedule and can either accept or reject an off-chain into its orderbook based on the fee parameters proposed by the order maker.

Payment should support at least ERC #20 and ERC #721 but perhaps any proposed transaction. The most generic method I can think of is to allow the subscriber to propose the payment as a list of at least 0 arbitrary transactions, all of which must be invoked together. As an example, the subscriber could propose to transfer a certain amount of a certain token in one transaction signed by their key and increment the subscription expiration date associated to them in the next transaction which will be signed by the provider in the proposed link. (I believe payment channels get the procedure of this correct.) The acceptable transactions would almost certainly be highly constrained to whitelisted contracts and methods to prevent arbitrary contract execution and exploits.

Depending on the service provided, its very likely there will be no way to verify a provider rendered the subscribed services without using an oracle. What is verifiable is the existence of a payment to that provider. For this reason, a prepay model of crediting is the pragmatic choice.

I'm fairly new to this but I do think we should try to think beyond what we are used to and instead try what is both pragmatic and possible.

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Apr 9, 2018

From the reddit thread:

Wonder if this might dovetail in some way with the recent discussion of requiring "rental" for blockchain space.

Article in coindesk about the same

owocki commented Apr 9, 2018

From the reddit thread:

Wonder if this might dovetail in some way with the recent discussion of requiring "rental" for blockchain space.

Article in coindesk about the same

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Apr 19, 2018

someone just mentioned to me that maybe somehow ethereum alarm clock could be built upon the standard. not saying i think its the right path. just putting that thought on the table

https://github.com/ethereum-alarm-clock/ethereum-alarm-clock

owocki commented Apr 19, 2018

someone just mentioned to me that maybe somehow ethereum alarm clock could be built upon the standard. not saying i think its the right path. just putting that thought on the table

https://github.com/ethereum-alarm-clock/ethereum-alarm-clock

@pipermerriam

This comment has been minimized.

Show comment
Hide comment
@pipermerriam

pipermerriam Apr 19, 2018

Member

@owocki I think you are correct with respect to the concept of recurring schedules (cron) which was always a planned feature.

Member

pipermerriam commented Apr 19, 2018

@owocki I think you are correct with respect to the concept of recurring schedules (cron) which was always a planned feature.

@kosecki123

This comment has been minimized.

Show comment
Hide comment
@kosecki123

kosecki123 Apr 20, 2018

@owocki this definitely can be built using ethereum alarm clock. The way eac works is more or less what @alexvandesande proposed, signed cheques.
An example implementation for DelayedPayment is quite close to something that can handle recurring payments.

Signed cheques approach using ETH makes user to deposit their funds on a contract that's going to used to serve subscriptions (subscription wallet). For e.g given annual subscription to deposit 12x payments upfront. One way to improve that is to wrap the ETH using WETH approach, and follow the allow/transferFrom functionality.

Alternatively users could fill the subscription wallet before subscription payment date, but that effectively makes this solution just an overhead, users can send the payment directly to provider instead.

kosecki123 commented Apr 20, 2018

@owocki this definitely can be built using ethereum alarm clock. The way eac works is more or less what @alexvandesande proposed, signed cheques.
An example implementation for DelayedPayment is quite close to something that can handle recurring payments.

Signed cheques approach using ETH makes user to deposit their funds on a contract that's going to used to serve subscriptions (subscription wallet). For e.g given annual subscription to deposit 12x payments upfront. One way to improve that is to wrap the ETH using WETH approach, and follow the allow/transferFrom functionality.

Alternatively users could fill the subscription wallet before subscription payment date, but that effectively makes this solution just an overhead, users can send the payment directly to provider instead.

@nieldlr

This comment has been minimized.

Show comment
Hide comment
@nieldlr

nieldlr Apr 20, 2018

Hey everyone,

I decided to start scratching around some experimental code to get a better idea in my head on how a standard might play out based mainly on @pipermerriam's ideas & what a few others have shared here: https://github.com/nieldlr/subscription-experiments

In my view, standardization should usually follow from actual use (bottom-up), or at least in close collaboration with defining a standard before hand (top-down). The reason why I mention this, is that after some experimentation I still believe that having the provider collect payments from each subscriber is not preferable.

My code above is not 100% optimized yet. I'm not the best solidity dev as I mentioned. If there's anyone that can upgrade these to make the flow smoother please do. Check out the tests + code for running simulations.

Even using batch payments, a token transfer usually is around 40,000 to 100,000 in gas costs. So for scaling purposes if you take a conservative approach a single collecting payment, 40,000, then you can feasibly have about 25 subscribers before the cost reaches 1mil in gas costs. As I mentioned, I already have 30 accounts funding me on StakeTree. So these gas costs reaches very unfeasible ranges very quickly.

In terms of scaling the protocol to account for these issues, it's very hard for me as a product dev to take these risks right now. Thus, I'd be happy to help with forming a standard that involves a payment per subscriptions setup, but it's not something I'd be comfortable in using at StakeTree right now.

This brings me back to standardization that follows use. I'd be curious from other projects who have implemented similar subscription-type systems how things have scaled for them and what optimizations they have considered. I'm struggling to see how subscriptions can scale if they don't funnel in to many:1 type of contract. Ie many subscribers pooling funds into a contract where the provider can withdraw from.

With that all said. I'd like to see more devs run simulations with my code or their own code (let's get the code out there and see what happens!). I'm not confident I have the best approach right now and might be getting these specs horribly wrong. I also really don't want to provide stop energy here. I want to keep seeing more ideas and possible ways to make this scale.

Thanks for reading.

nieldlr commented Apr 20, 2018

Hey everyone,

I decided to start scratching around some experimental code to get a better idea in my head on how a standard might play out based mainly on @pipermerriam's ideas & what a few others have shared here: https://github.com/nieldlr/subscription-experiments

In my view, standardization should usually follow from actual use (bottom-up), or at least in close collaboration with defining a standard before hand (top-down). The reason why I mention this, is that after some experimentation I still believe that having the provider collect payments from each subscriber is not preferable.

My code above is not 100% optimized yet. I'm not the best solidity dev as I mentioned. If there's anyone that can upgrade these to make the flow smoother please do. Check out the tests + code for running simulations.

Even using batch payments, a token transfer usually is around 40,000 to 100,000 in gas costs. So for scaling purposes if you take a conservative approach a single collecting payment, 40,000, then you can feasibly have about 25 subscribers before the cost reaches 1mil in gas costs. As I mentioned, I already have 30 accounts funding me on StakeTree. So these gas costs reaches very unfeasible ranges very quickly.

In terms of scaling the protocol to account for these issues, it's very hard for me as a product dev to take these risks right now. Thus, I'd be happy to help with forming a standard that involves a payment per subscriptions setup, but it's not something I'd be comfortable in using at StakeTree right now.

This brings me back to standardization that follows use. I'd be curious from other projects who have implemented similar subscription-type systems how things have scaled for them and what optimizations they have considered. I'm struggling to see how subscriptions can scale if they don't funnel in to many:1 type of contract. Ie many subscribers pooling funds into a contract where the provider can withdraw from.

With that all said. I'd like to see more devs run simulations with my code or their own code (let's get the code out there and see what happens!). I'm not confident I have the best approach right now and might be getting these specs horribly wrong. I also really don't want to provide stop energy here. I want to keep seeing more ideas and possible ways to make this scale.

Thanks for reading.

@androolloyd

This comment has been minimized.

Show comment
Hide comment
@androolloyd

androolloyd May 1, 2018

@kermankohli Would love to connect, what you're describing is a lot like what we're doing for Groundhog(https://Groundhog.network).

If you're able to make the call would love to connect afterwards.

androolloyd commented May 1, 2018

@kermankohli Would love to connect, what you're describing is a lot like what we're doing for Groundhog(https://Groundhog.network).

If you're able to make the call would love to connect afterwards.

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki May 1, 2018

@kermankohli we missed you on the call! can you make the next one?

for everyone else on the thread, here are our notes from the first call: https://docs.google.com/document/d/1P1fhGAJS_IYubUUEHEmPpg2ltjMZy7PR5Ot8xuJRbS8/edit#

please email me (kevin@gitcoin.co) or join the https://gitcoin.co/slack if you are interested in being in the conversation. we have a subscriptions channel there that were all hanging out in

owocki commented May 1, 2018

@kermankohli we missed you on the call! can you make the next one?

for everyone else on the thread, here are our notes from the first call: https://docs.google.com/document/d/1P1fhGAJS_IYubUUEHEmPpg2ltjMZy7PR5Ot8xuJRbS8/edit#

please email me (kevin@gitcoin.co) or join the https://gitcoin.co/slack if you are interested in being in the conversation. we have a subscriptions channel there that were all hanging out in

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki May 1, 2018

@owocki Just got the invite and turns out the event is 12am for me today (Sydney, Australia). Is there any way we could pull back the meeting 3 hours or reschedule it?

the only thing is that we have someone in europe on the call. ack timezones are a pain. let me see what i can do.. would love to have you on the next one @kermankohli

owocki commented May 1, 2018

@owocki Just got the invite and turns out the event is 12am for me today (Sydney, Australia). Is there any way we could pull back the meeting 3 hours or reschedule it?

the only thing is that we have someone in europe on the call. ack timezones are a pain. let me see what i can do.. would love to have you on the next one @kermankohli

@kermankohli

This comment has been minimized.

Show comment
Hide comment
@kermankohli

kermankohli May 2, 2018

@androolloyd Hey man, sounds good! Unfortunately I couldn't make the call since it was 12am for me although would love to setup a meeting otherwise.

@owocki Ah sorry about being a pain for timezones - I can stay awake till 10:30pm and can get up by 5:30am (weekdays) in case that helps? Also only working part-time Mon-Wed so the other days are pretty flexible.

kermankohli commented May 2, 2018

@androolloyd Hey man, sounds good! Unfortunately I couldn't make the call since it was 12am for me although would love to setup a meeting otherwise.

@owocki Ah sorry about being a pain for timezones - I can stay awake till 10:30pm and can get up by 5:30am (weekdays) in case that helps? Also only working part-time Mon-Wed so the other days are pretty flexible.

@Josephrp

This comment has been minimized.

Show comment
Hide comment
@Josephrp

Josephrp May 2, 2018

Josephrp commented May 2, 2018

@androolloyd

This comment has been minimized.

Show comment
Hide comment
@androolloyd

androolloyd commented May 2, 2018

@Josephrp cool project

@johngriffin

This comment has been minimized.

Show comment
Hide comment
@johngriffin

johngriffin May 2, 2018

Hi everyone,

I’ve been following this discussion and thinking about this problem for a while. I recently wrote a blog post and some POC code on the separate but related topic of tokenizing SaaS licenses, and I previously founded a non-crypto SaaS company so I’m most interested in the SaaS use case and I tend to use Stripe as my benchmark from the fiat world.

I just wanted to summarise and clarify my understanding of a few things, picking up on some points in the conversation around the 8x paper.

Firstly, the 8x paper is great, kudos @kermankohli. I think that there are some aspects of it that should be supported by an open standard but not necessarily specified in the standard. These are things that I think still fully make sense to be part of a protocol like 8x, but that we should probably separate out. For example:

  1. Use of Dai as the payment currency, we should probably define support for any ERC-20 token.
  2. Use of the 8x token to reward processors, this could be done with any token / eth.
  3. There should probably be some way for you to ensure you process your own payments if you wish, so you can still create standards-compliant subscriptions but white-list just yourself as the processor.
  4. The 1% reward figure for payment processors. Based on some back-of-a-matchbox maths it seems this would need to increase in the case that a payment amount was less than $8. Assuming it costs 40k gas to do the transfer() and gas price is 3Gwei, that would cost $0.08 today. I guess that at a minimum we need a reward percentage with an absolute minimum.

@kermankohl you mention to @nieldlr here that you had a way to solve the gas cost problem. I'm not sure if I'm missing something big here, do you mean there's a way to reduce the cost below a transfer() call per subscriber each billing period?

@nieldlr in response to your extra question 4 above - I believe that the processor reward increases with time to disincentive the payment being processed early. In the paper it says that the game theory and mechanics around this haven't been fully fleshed out yet but I guess we could also put some time lock around the payment?

Anyway, this is a really great start! I hope to join the call next week and I'll ask join the slack as it may be easier to discuss over there.

johngriffin commented May 2, 2018

Hi everyone,

I’ve been following this discussion and thinking about this problem for a while. I recently wrote a blog post and some POC code on the separate but related topic of tokenizing SaaS licenses, and I previously founded a non-crypto SaaS company so I’m most interested in the SaaS use case and I tend to use Stripe as my benchmark from the fiat world.

I just wanted to summarise and clarify my understanding of a few things, picking up on some points in the conversation around the 8x paper.

Firstly, the 8x paper is great, kudos @kermankohli. I think that there are some aspects of it that should be supported by an open standard but not necessarily specified in the standard. These are things that I think still fully make sense to be part of a protocol like 8x, but that we should probably separate out. For example:

  1. Use of Dai as the payment currency, we should probably define support for any ERC-20 token.
  2. Use of the 8x token to reward processors, this could be done with any token / eth.
  3. There should probably be some way for you to ensure you process your own payments if you wish, so you can still create standards-compliant subscriptions but white-list just yourself as the processor.
  4. The 1% reward figure for payment processors. Based on some back-of-a-matchbox maths it seems this would need to increase in the case that a payment amount was less than $8. Assuming it costs 40k gas to do the transfer() and gas price is 3Gwei, that would cost $0.08 today. I guess that at a minimum we need a reward percentage with an absolute minimum.

@kermankohl you mention to @nieldlr here that you had a way to solve the gas cost problem. I'm not sure if I'm missing something big here, do you mean there's a way to reduce the cost below a transfer() call per subscriber each billing period?

@nieldlr in response to your extra question 4 above - I believe that the processor reward increases with time to disincentive the payment being processed early. In the paper it says that the game theory and mechanics around this haven't been fully fleshed out yet but I guess we could also put some time lock around the payment?

Anyway, this is a really great start! I hope to join the call next week and I'll ask join the slack as it may be easier to discuss over there.

@kermankohli

This comment has been minimized.

Show comment
Hide comment
@kermankohli

kermankohli May 2, 2018

@johngriffin Thanks for taking the time to read through it and writing all of that up!

  1. Definitely. Already added support for this by adding a tokenAddress variable in the subscription struct. https://github.com/8x-protocol/8x-protocol/blob/master/contracts/VolumeSubscription.sol.

  2. Processors are rewarded in whatever token is used for the transaction (mainly Dai in this case). 8x tokens are simply used for staking to claim a payment and governance.

  3. That's a pretty cool idea - although what could be some use cases for it?

4 In addition to the 1% fee, there will also be a flat fee of ~ $0.10. Not exactly sure how this would vary over time but essentially businesses will pay for the gas fee, not processors or users.

  1. With @nieldlr's method, essentially you have to use loops in order to do pay outs which means you run into gas cost issues very quickly. With 8x, when a processor executes a transaction the money is immediately transferred to the business. There isn't a need to do any kind of loops. But overall I don't think there is a way to reduce the cost below a transfer (unless you use pull based payments but there's still the issue of taking money out and paying to do that).

Let me know if you have any questions/comments on the above - keen to speak with you at the next call!

kermankohli commented May 2, 2018

@johngriffin Thanks for taking the time to read through it and writing all of that up!

  1. Definitely. Already added support for this by adding a tokenAddress variable in the subscription struct. https://github.com/8x-protocol/8x-protocol/blob/master/contracts/VolumeSubscription.sol.

  2. Processors are rewarded in whatever token is used for the transaction (mainly Dai in this case). 8x tokens are simply used for staking to claim a payment and governance.

  3. That's a pretty cool idea - although what could be some use cases for it?

4 In addition to the 1% fee, there will also be a flat fee of ~ $0.10. Not exactly sure how this would vary over time but essentially businesses will pay for the gas fee, not processors or users.

  1. With @nieldlr's method, essentially you have to use loops in order to do pay outs which means you run into gas cost issues very quickly. With 8x, when a processor executes a transaction the money is immediately transferred to the business. There isn't a need to do any kind of loops. But overall I don't think there is a way to reduce the cost below a transfer (unless you use pull based payments but there's still the issue of taking money out and paying to do that).

Let me know if you have any questions/comments on the above - keen to speak with you at the next call!

@johngriffin

This comment has been minimized.

Show comment
Hide comment
@johngriffin

johngriffin May 14, 2018

@kermankohli Hey! Thanks for clarifying those points.

  1. My thinking was that the most basic version of a recurring payments standard should be implementable with no more actors than subscriber and provider. It shouldn't have to depend on a network of processors, and if there were such a network you may wish to opt-out. Hence my suggestion of being able to only white-list yourself as the processor for a subscription is effectively a way to do that.

johngriffin commented May 14, 2018

@kermankohli Hey! Thanks for clarifying those points.

  1. My thinking was that the most basic version of a recurring payments standard should be implementable with no more actors than subscriber and provider. It shouldn't have to depend on a network of processors, and if there were such a network you may wish to opt-out. Hence my suggestion of being able to only white-list yourself as the processor for a subscription is effectively a way to do that.
@kermankohli

This comment has been minimized.

Show comment
Hide comment
@kermankohli

kermankohli May 18, 2018

Hey everyone,

Following on from this thread you can track progress of the 8x Protocol at:

Telegram: https://t.me/joinchat/AXlpZ1LUmBqu3ySXHVh8qA
Website: http://8xprotocol.com/
Twitter: https://twitter.com/8x_Protocol

I'll also be doing daily vlogs for this at: https://www.youtube.com/playlist?list=PLdm5dK5Ob2TnSUKlcYj3XfCO-iS8SeEfb

kermankohli commented May 18, 2018

Hey everyone,

Following on from this thread you can track progress of the 8x Protocol at:

Telegram: https://t.me/joinchat/AXlpZ1LUmBqu3ySXHVh8qA
Website: http://8xprotocol.com/
Twitter: https://twitter.com/8x_Protocol

I'll also be doing daily vlogs for this at: https://www.youtube.com/playlist?list=PLdm5dK5Ob2TnSUKlcYj3XfCO-iS8SeEfb

@johngriffin

This comment has been minimized.

Show comment
Hide comment
@johngriffin

johngriffin May 29, 2018

Hi all,

@Davidkobro and I have started work on an implementation based on @sb777's spec. Doing this has raised a number of questions and decisions that need to be made. I’ve pushed the code in it’s current incomplete state here, at the moment the core functions createSubscription() and processPayment() are in a working state dealing with periodTypes of seconds only.

https://github.com/johngriffin/ERC948/blob/master/contracts/ERC948.sol

Discussion points

  • If we allow payeeAddress to be set by the subscriber when they createSubscription() we probably need the contract to contain a whitelist of valid payeeAddresses. Perhaps there other constraints on valid subscriptions that the payee might want to implement when deploying the contract - e.g. only certain tokens / amounts are valid.
  • What is the purpose of isToken in the signature for createSubscription() ? Surely all payments have to be in tokens rather than ether as you can't delegate authority for a contract to move ether from your wallet in future.
  • Should we allow externalSubId? It seems preferable for a unique ID to be generated by the contract, otherwise the caller of createSubscription may have to make multiple transactions in the case that their chosen Id already exists.
  • If a payment is not collected in one billing period then we allow this payment to be collected at a later date provided the subscription is still active. Added “active” flag to subscription struct to handle this. This means that when a payment is processed we increment the nextPaymentDate by one billing period only, rather than set it to now() + billingPeriod.
  • I propose that in createSubscription we set nextPaymentTime to _startTime. So _startTime will be the time that the first recurring payment is made. The amountInitial will be taken immediately as createSubscription is executed.
  • processPayment() will only process one payment for one subscription at a time. If there are multiple billing periods for which payments haven’t been processed on a given subscription, then a transaction will have to be made for each of them. Of course it is possible to make a more efficient way of collecting these but doesn’t need to be part of the spec.
  • Date math - the pipermeriam library looks good but it only deals with date units as points in time. It does not deal with time intervals or date maths. E.g. when we are on month 12 and we want to increment the nextPaymentTime by a month, it can’t tell us how to do this. I’m reluctant to implement a date/time math library so if anyone has any alternatives suggestions I’d love to know.

Scott - what’s the best way to collaborate on the spec? I guess I could make comments on the issue?

johngriffin commented May 29, 2018

Hi all,

@Davidkobro and I have started work on an implementation based on @sb777's spec. Doing this has raised a number of questions and decisions that need to be made. I’ve pushed the code in it’s current incomplete state here, at the moment the core functions createSubscription() and processPayment() are in a working state dealing with periodTypes of seconds only.

https://github.com/johngriffin/ERC948/blob/master/contracts/ERC948.sol

Discussion points

  • If we allow payeeAddress to be set by the subscriber when they createSubscription() we probably need the contract to contain a whitelist of valid payeeAddresses. Perhaps there other constraints on valid subscriptions that the payee might want to implement when deploying the contract - e.g. only certain tokens / amounts are valid.
  • What is the purpose of isToken in the signature for createSubscription() ? Surely all payments have to be in tokens rather than ether as you can't delegate authority for a contract to move ether from your wallet in future.
  • Should we allow externalSubId? It seems preferable for a unique ID to be generated by the contract, otherwise the caller of createSubscription may have to make multiple transactions in the case that their chosen Id already exists.
  • If a payment is not collected in one billing period then we allow this payment to be collected at a later date provided the subscription is still active. Added “active” flag to subscription struct to handle this. This means that when a payment is processed we increment the nextPaymentDate by one billing period only, rather than set it to now() + billingPeriod.
  • I propose that in createSubscription we set nextPaymentTime to _startTime. So _startTime will be the time that the first recurring payment is made. The amountInitial will be taken immediately as createSubscription is executed.
  • processPayment() will only process one payment for one subscription at a time. If there are multiple billing periods for which payments haven’t been processed on a given subscription, then a transaction will have to be made for each of them. Of course it is possible to make a more efficient way of collecting these but doesn’t need to be part of the spec.
  • Date math - the pipermeriam library looks good but it only deals with date units as points in time. It does not deal with time intervals or date maths. E.g. when we are on month 12 and we want to increment the nextPaymentTime by a month, it can’t tell us how to do this. I’m reluctant to implement a date/time math library so if anyone has any alternatives suggestions I’d love to know.

Scott - what’s the best way to collaborate on the spec? I guess I could make comments on the issue?

@nathantr

This comment has been minimized.

Show comment
Hide comment
@nathantr

nathantr May 30, 2018

Wanted to add thoughts to @johngriffin's points above, also have the same question @sb777 on best way to collaborate on the spec?

  • Agree that there's a deeper topic here around what variables a subscriber might want to set and be in control of when creating the subscription. Although the merchant initiates the creation, this is with data from the subscriber and so we should be cognizant of what power should remain with the subscriber.

  • ExternalSubId it would be great it if there was an option for it to be both generated automatically or to be set by the merchant. Most merchants will have their own unique reference generated from their own systems, or use a unique identifier generated by the protocol.

  • Regarding payments and billing periods, let's be clear there's subscriptions, which handle describing the nature of the customer relationship, billing, which handles indicating how a customer should be invoiced, and payment, which handles how a customer should pay. Each of these is a deep domain within themselves. We could take the stance that the protocol should allow full flexibility and let the merchant bill on any day and let the subscriber pay on any day, or we constrain it (as I think @johngriffin is suggesting?) and say the merchant can only bill at a certain time and the subscriber can only pay at a certain time.

I think this may be a deeper topic as well to delve into.

Finally as a more general comment on the spec, there is a pauseSubscription method but then how do you resume? There are many reasons to want to resume a paused Subscription e.g., subscriber goes on vacation etc.

nathantr commented May 30, 2018

Wanted to add thoughts to @johngriffin's points above, also have the same question @sb777 on best way to collaborate on the spec?

  • Agree that there's a deeper topic here around what variables a subscriber might want to set and be in control of when creating the subscription. Although the merchant initiates the creation, this is with data from the subscriber and so we should be cognizant of what power should remain with the subscriber.

  • ExternalSubId it would be great it if there was an option for it to be both generated automatically or to be set by the merchant. Most merchants will have their own unique reference generated from their own systems, or use a unique identifier generated by the protocol.

  • Regarding payments and billing periods, let's be clear there's subscriptions, which handle describing the nature of the customer relationship, billing, which handles indicating how a customer should be invoiced, and payment, which handles how a customer should pay. Each of these is a deep domain within themselves. We could take the stance that the protocol should allow full flexibility and let the merchant bill on any day and let the subscriber pay on any day, or we constrain it (as I think @johngriffin is suggesting?) and say the merchant can only bill at a certain time and the subscriber can only pay at a certain time.

I think this may be a deeper topic as well to delve into.

Finally as a more general comment on the spec, there is a pauseSubscription method but then how do you resume? There are many reasons to want to resume a paused Subscription e.g., subscriber goes on vacation etc.

@kosecki123

This comment has been minimized.

Show comment
Hide comment
@kosecki123

kosecki123 May 31, 2018

Date math - the pipermeriam library looks good but it only deals with date units as points in time. It does not deal with time intervals or date maths. E.g. when we are on month 12 and we want to increment the nextPaymentTime by a month, it can’t tell us how to do this. I’m reluctant to implement a date/time math library so if anyone has any alternatives suggestions I’d love to know.

@johngriffin I came accros this library https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary from @bokkypoobah

kosecki123 commented May 31, 2018

Date math - the pipermeriam library looks good but it only deals with date units as points in time. It does not deal with time intervals or date maths. E.g. when we are on month 12 and we want to increment the nextPaymentTime by a month, it can’t tell us how to do this. I’m reluctant to implement a date/time math library so if anyone has any alternatives suggestions I’d love to know.

@johngriffin I came accros this library https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary from @bokkypoobah

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Jun 1, 2018

hey everyone.. ( i mean this in the least shill-ey way possible ) the working group creating this standard is really starting to pick up steam...

if you want to join... there is a slakc channel here => https://gitcoin.co/slack -- msg me and ill invite you to it
and here are our notes https://docs.google.com/document/d/1P1fhGAJS_IYubUUEHEmPpg2ltjMZy7PR5Ot8xuJRbS8/edit#

owocki commented Jun 1, 2018

hey everyone.. ( i mean this in the least shill-ey way possible ) the working group creating this standard is really starting to pick up steam...

if you want to join... there is a slakc channel here => https://gitcoin.co/slack -- msg me and ill invite you to it
and here are our notes https://docs.google.com/document/d/1P1fhGAJS_IYubUUEHEmPpg2ltjMZy7PR5Ot8xuJRbS8/edit#

@keymethod

This comment has been minimized.

Show comment
Hide comment
@keymethod

keymethod Jun 7, 2018

What are the advantage of a new token over designing a wallet that would send recurring payments at set periods? I'm thinking that this proposed token is advantageous for accounting and payment management of the service provider, how about the user?

keymethod commented Jun 7, 2018

What are the advantage of a new token over designing a wallet that would send recurring payments at set periods? I'm thinking that this proposed token is advantageous for accounting and payment management of the service provider, how about the user?

@sb777

This comment has been minimized.

Show comment
Hide comment
@sb777

sb777 Jun 7, 2018

Awesome work @johngriffin and @Davidkobro!

If we allow payeeAddress to be set by the subscriber when they createSubscription() we probably need the contract to contain a whitelist of valid payeeAddresses.

Do you mean, set up before the call to createSubscription, to compare against, or afterwards to keep track of which address was set?

Perhaps there other constraints on valid subscriptions that the payee might want to implement when deploying the contract - e.g. only certain tokens / amounts are valid.

I think so. My instinct is to leave the implementation of this outside of the spec, and just revert().

What is the purpose of isToken in the signature for createSubscription() ? Surely all payments have to be in tokens rather than ether as you can't delegate authority for a contract to move ether from your wallet in future.

Sorry, this was not clear enough. Let me expand a bit on the thinking behind this.

The model we're proposing would allow ETH as well by essentially creating an "escrow" wallet contract for all your subscriptions, where the wallet contract itself holds the funds/tokens, which would enable it to send out both ether and tokens.

The subscriber contract needs a whitelist of addresses which can call the subscriber-side management functions. At minimum, this can be the owner/contract deployer. In Groundhog, we are allowing user to authorize multiple devices/wallets (hw wallet, browser extension, Groundhog mobile wallet, other mobile wallet). Other contracts could even be whitelisted depending on what functionality people want to introduce. But in general our thinking is leave that up to the implementer.

processPayment() will only process one payment for one subscription at a time. If there are multiple billing periods for which payments haven’t been processed on a given subscription, then a transaction will have to be made for each of them. Of course it is possible to make a more efficient way of collecting these but doesn’t need to be part of the spec.

This is an interesting point. There was some discussion of whether "outstanding due payments" should be all sent at once or pulled one at a time. I'm inclined to think that processPayment should behave like a call to a credit card or a bank account - always have a value parameter and pull only that value, success/fail -- but -- if there are further outstanding payment amounts, multiple/subsequent calls can be made until there is no more available/due.

One other thought - Since one of the use cases we are trying to enable is the iTunes/API model, where you can approve up to X amount, and make subsequent calls throughout the period as that balance is spent - I wonder if we should add a mode flag on subscriptions to indicate this subscription type, so that balances don't roll over by period.

For example, if I'm authorizing an iTunes style subscription for up to $20/month, I don't want unspent amount to roll over into the next period as available balance. Maybe an unspentRollover flag?

The reason this is needed is, if it's just a garden variety $20/month SaSS subscription, if for whatever reason the merchant calls the subscriber wallet for a $10 payment, it should then be able to call another subsequent $10 payment in order to bill the full due amount. The only other way to do it would be to not specify a billing amount in the call, and just have the contract send the entire amount that's due when processSubscription is called. Then to enable the iTunes model, a flag could be set for discretePayments in which case a value is required for processSubscription.

So if we want to enable both "whole amount" billing and "up to billing" for the two identified use cases, it seems that we need either unspentRollover or discretePayments as a flag when creating the subscription. (there may be better names for these variables.)

And to @nathantr's point about subscriptions vs payments, I wonder if the function should actually be called processPayment rather than processSubscription.

sb777 commented Jun 7, 2018

Awesome work @johngriffin and @Davidkobro!

If we allow payeeAddress to be set by the subscriber when they createSubscription() we probably need the contract to contain a whitelist of valid payeeAddresses.

Do you mean, set up before the call to createSubscription, to compare against, or afterwards to keep track of which address was set?

Perhaps there other constraints on valid subscriptions that the payee might want to implement when deploying the contract - e.g. only certain tokens / amounts are valid.

I think so. My instinct is to leave the implementation of this outside of the spec, and just revert().

What is the purpose of isToken in the signature for createSubscription() ? Surely all payments have to be in tokens rather than ether as you can't delegate authority for a contract to move ether from your wallet in future.

Sorry, this was not clear enough. Let me expand a bit on the thinking behind this.

The model we're proposing would allow ETH as well by essentially creating an "escrow" wallet contract for all your subscriptions, where the wallet contract itself holds the funds/tokens, which would enable it to send out both ether and tokens.

The subscriber contract needs a whitelist of addresses which can call the subscriber-side management functions. At minimum, this can be the owner/contract deployer. In Groundhog, we are allowing user to authorize multiple devices/wallets (hw wallet, browser extension, Groundhog mobile wallet, other mobile wallet). Other contracts could even be whitelisted depending on what functionality people want to introduce. But in general our thinking is leave that up to the implementer.

processPayment() will only process one payment for one subscription at a time. If there are multiple billing periods for which payments haven’t been processed on a given subscription, then a transaction will have to be made for each of them. Of course it is possible to make a more efficient way of collecting these but doesn’t need to be part of the spec.

This is an interesting point. There was some discussion of whether "outstanding due payments" should be all sent at once or pulled one at a time. I'm inclined to think that processPayment should behave like a call to a credit card or a bank account - always have a value parameter and pull only that value, success/fail -- but -- if there are further outstanding payment amounts, multiple/subsequent calls can be made until there is no more available/due.

One other thought - Since one of the use cases we are trying to enable is the iTunes/API model, where you can approve up to X amount, and make subsequent calls throughout the period as that balance is spent - I wonder if we should add a mode flag on subscriptions to indicate this subscription type, so that balances don't roll over by period.

For example, if I'm authorizing an iTunes style subscription for up to $20/month, I don't want unspent amount to roll over into the next period as available balance. Maybe an unspentRollover flag?

The reason this is needed is, if it's just a garden variety $20/month SaSS subscription, if for whatever reason the merchant calls the subscriber wallet for a $10 payment, it should then be able to call another subsequent $10 payment in order to bill the full due amount. The only other way to do it would be to not specify a billing amount in the call, and just have the contract send the entire amount that's due when processSubscription is called. Then to enable the iTunes model, a flag could be set for discretePayments in which case a value is required for processSubscription.

So if we want to enable both "whole amount" billing and "up to billing" for the two identified use cases, it seems that we need either unspentRollover or discretePayments as a flag when creating the subscription. (there may be better names for these variables.)

And to @nathantr's point about subscriptions vs payments, I wonder if the function should actually be called processPayment rather than processSubscription.

@sb777

This comment has been minimized.

Show comment
Hide comment
@sb777

sb777 Jun 7, 2018

Oh, and just to introduce myself to the people on the thread I haven't met yet, I'm Scott, one of the co-founders of The Groundhog Network, along with @androolloyd. We're building Groundhog to supercharge Ethereum e-commerce.

Introducing Groundhog: https://medium.com/groundhog-network/introducing-groundhog-a1099f98ae84

sb777 commented Jun 7, 2018

Oh, and just to introduce myself to the people on the thread I haven't met yet, I'm Scott, one of the co-founders of The Groundhog Network, along with @androolloyd. We're building Groundhog to supercharge Ethereum e-commerce.

Introducing Groundhog: https://medium.com/groundhog-network/introducing-groundhog-a1099f98ae84

@johngriffin

This comment has been minimized.

Show comment
Hide comment
@johngriffin

johngriffin Jun 9, 2018

Hey, so following the last call and chat on slack I just wanted to put forward what I propose to be the most important topics that we need to agree on. There are lots of great ideas flying around but we need to decide what should and shouldn't be part of this standard in order that we can agree on the technical spec.

Why does this need to be an ERC standard?
Anyone can create and implement a smart contract that has this functionality, what is the advantage in defining a standard interface? Answering this question should help us to answer all the other questions about what should / shouldn’t be included in the standard.

I suggest the reason for this standard is interoperability - we want wallets to understand that you’re about to sign a recurring payment contract so that they can present you with a UI that summarises the agreement you’re about to enter into. As your wallet now knows you’ve entered into a subscription contract it can also provide appropriate UI for managing and cancelling your subscriptions in future.

Should the standard deal with ETH escrow or just ERC-20 token payments?

  • Option 1 - payments must be made with ERC-20 tokens. The tokens remain in the subscriber’s wallet until a valid payment is requested by the merchant. The contract then transfers tokens directly from the subscribers wallet to the merchant.

  • Option 2 - (copied from @sb777 's post above) - The model we're proposing would allow ETH as well by essentially creating an "escrow" wallet contract for all your subscriptions, where the wallet contract itself holds the funds/tokens, which would enable it to send out both ether and tokens. The subscriber contract needs a whitelist of addresses which can call the subscriber-side management functions. At minimum, this can be the owner/contract deployer. In Groundhog, we are allowing user to authorize multiple devices/wallets (hw wallet, browser extension, Groundhog mobile wallet, other mobile wallet). Other contracts could even be whitelisted depending on what functionality people want to introduce. But in general our thinking is leave that up to the implementer.

Rules around payments and billing periods
As @nathantr pointed out above it’s important to define the terms “billing” and “payment”. So we have billing periods and then payments that can be “pulled” within those billing periods. When the subscription is created there is a maximum amount that can be pulled per billing period.

  • Do we want to support multiple payments being pulled per billing period, upto the maximum
    allowance? Or merchant can only pull one payment per billing period.

  • Do we want to support pulling payments for past billing periods that have already elapsed, like a roll-over? See unspentRollover flag as mentioned by @sb777.

johngriffin commented Jun 9, 2018

Hey, so following the last call and chat on slack I just wanted to put forward what I propose to be the most important topics that we need to agree on. There are lots of great ideas flying around but we need to decide what should and shouldn't be part of this standard in order that we can agree on the technical spec.

Why does this need to be an ERC standard?
Anyone can create and implement a smart contract that has this functionality, what is the advantage in defining a standard interface? Answering this question should help us to answer all the other questions about what should / shouldn’t be included in the standard.

I suggest the reason for this standard is interoperability - we want wallets to understand that you’re about to sign a recurring payment contract so that they can present you with a UI that summarises the agreement you’re about to enter into. As your wallet now knows you’ve entered into a subscription contract it can also provide appropriate UI for managing and cancelling your subscriptions in future.

Should the standard deal with ETH escrow or just ERC-20 token payments?

  • Option 1 - payments must be made with ERC-20 tokens. The tokens remain in the subscriber’s wallet until a valid payment is requested by the merchant. The contract then transfers tokens directly from the subscribers wallet to the merchant.

  • Option 2 - (copied from @sb777 's post above) - The model we're proposing would allow ETH as well by essentially creating an "escrow" wallet contract for all your subscriptions, where the wallet contract itself holds the funds/tokens, which would enable it to send out both ether and tokens. The subscriber contract needs a whitelist of addresses which can call the subscriber-side management functions. At minimum, this can be the owner/contract deployer. In Groundhog, we are allowing user to authorize multiple devices/wallets (hw wallet, browser extension, Groundhog mobile wallet, other mobile wallet). Other contracts could even be whitelisted depending on what functionality people want to introduce. But in general our thinking is leave that up to the implementer.

Rules around payments and billing periods
As @nathantr pointed out above it’s important to define the terms “billing” and “payment”. So we have billing periods and then payments that can be “pulled” within those billing periods. When the subscription is created there is a maximum amount that can be pulled per billing period.

  • Do we want to support multiple payments being pulled per billing period, upto the maximum
    allowance? Or merchant can only pull one payment per billing period.

  • Do we want to support pulling payments for past billing periods that have already elapsed, like a roll-over? See unspentRollover flag as mentioned by @sb777.

@nathantr

This comment has been minimized.

Show comment
Hide comment
@nathantr

nathantr Jun 10, 2018

Some great points @johngriffin. I can't say I fully follow the options @sb777 is proposing for ETH vs ERC-20, but having a single wallet that holds all your subscriptions definitely sounds appealing. Half of the problem of subscriptions is simply keeping track and being in control of all of them.

Re: payments and billing periods. I think having a notion of billing period is necessary (this is the periodType in the proposed spec I presume), and then pulling multiple payments per billing period would allow you to service a broader range of use cases. E.g., usage. If I as the merchant charge 1 USD per GB of Storage, then I am allowed to charge you up to, say, $10 for 10 GB of Storage. At which point you would need either raise the "cap" or start a higher cap subscription relationship with me.

The unspentRollover question I would be less in favor simply because of the complexity it creates. It really, at least to me, seems to be a flag that favors more advanced usage based billing use cases, and not sure if in a standard we want to start tracking some notion of unspent "credits". It would be great if this is something the implementer could do, e.g. they could check for the unspent amount and then use that to alter the "limit" of the subscription in the subsequent period, without needing the standard to do so explicitly.

I'd be an advocate for keeping it simple, and saying you can pull any amount of payments you want in a certain period up to an authorized limit. But it's a use it or lose it type deal, and anything unused does not get rolled over into the next period.

nathantr commented Jun 10, 2018

Some great points @johngriffin. I can't say I fully follow the options @sb777 is proposing for ETH vs ERC-20, but having a single wallet that holds all your subscriptions definitely sounds appealing. Half of the problem of subscriptions is simply keeping track and being in control of all of them.

Re: payments and billing periods. I think having a notion of billing period is necessary (this is the periodType in the proposed spec I presume), and then pulling multiple payments per billing period would allow you to service a broader range of use cases. E.g., usage. If I as the merchant charge 1 USD per GB of Storage, then I am allowed to charge you up to, say, $10 for 10 GB of Storage. At which point you would need either raise the "cap" or start a higher cap subscription relationship with me.

The unspentRollover question I would be less in favor simply because of the complexity it creates. It really, at least to me, seems to be a flag that favors more advanced usage based billing use cases, and not sure if in a standard we want to start tracking some notion of unspent "credits". It would be great if this is something the implementer could do, e.g. they could check for the unspent amount and then use that to alter the "limit" of the subscription in the subsequent period, without needing the standard to do so explicitly.

I'd be an advocate for keeping it simple, and saying you can pull any amount of payments you want in a certain period up to an authorized limit. But it's a use it or lose it type deal, and anything unused does not get rolled over into the next period.

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Jun 14, 2018

Update: The group will be using this repo to collaborate on the EIP: https://github.com/EthereumOpenSubscriptions/standard

owocki commented Jun 14, 2018

Update: The group will be using this repo to collaborate on the EIP: https://github.com/EthereumOpenSubscriptions/standard

@Bergqvisten

This comment has been minimized.

Show comment
Hide comment
@Bergqvisten

Bergqvisten Jun 19, 2018

Hello everyone,

Thanks for the interesting read, I very much agree that there should be a standard for this type of service. What do you think of adding a timeSubscribed variable to keep track of the time a customer has been subscribed? A lot of subscription services appreciate loyal customers and often reward long time subscribers. The reason block.timestamp - startTime isn't enough for keeping track of this is because of the pauseSubscription() function, which will create empty time slots that shouldn't be counted.

Bergqvisten commented Jun 19, 2018

Hello everyone,

Thanks for the interesting read, I very much agree that there should be a standard for this type of service. What do you think of adding a timeSubscribed variable to keep track of the time a customer has been subscribed? A lot of subscription services appreciate loyal customers and often reward long time subscribers. The reason block.timestamp - startTime isn't enough for keeping track of this is because of the pauseSubscription() function, which will create empty time slots that shouldn't be counted.

@nathantr

This comment has been minimized.

Show comment
Hide comment
@nathantr

nathantr Jun 20, 2018

@Bergqvisten welcome! I think while pause resume does tend to throw off the notion of how long you have been an active subscriber, it doesn't affect the fact you may have signed up, for example, for a 12 month subscription. As long as you know when the pause and resume happened you could then calculate the impact on the "active" subscription length.

Typically with pause/resume you might build in a parameter to automatically extend the subscription when you resume, if you know it. that might be nice @sb777

nathantr commented Jun 20, 2018

@Bergqvisten welcome! I think while pause resume does tend to throw off the notion of how long you have been an active subscriber, it doesn't affect the fact you may have signed up, for example, for a 12 month subscription. As long as you know when the pause and resume happened you could then calculate the impact on the "active" subscription length.

Typically with pause/resume you might build in a parameter to automatically extend the subscription when you resume, if you know it. that might be nice @sb777

@Bergqvisten

This comment has been minimized.

Show comment
Hide comment
@Bergqvisten

Bergqvisten Jun 20, 2018

Thanks @nathantr! You're right, that would totally work for a subscription plan with a specified length. I think the implementation I had in mind was a little bit different, hence the requirement for a total time subscribed.

I read about the problem of gas cost earlier in the thread. Is this something that has been solved to an acceptable degree yet?

Bergqvisten commented Jun 20, 2018

Thanks @nathantr! You're right, that would totally work for a subscription plan with a specified length. I think the implementation I had in mind was a little bit different, hence the requirement for a total time subscribed.

I read about the problem of gas cost earlier in the thread. Is this something that has been solved to an acceptable degree yet?

@kosecki123

This comment has been minimized.

Show comment
Hide comment
@kosecki123

kosecki123 Jun 21, 2018

As an extension to @pipermerriam proposal, I think having definitions for functions to return the status of the subscription would be beneficial

  • isFunded() returns bool: returns true if there is currently enough funds (ETH or tokens, depending on implementation) available for provider to collect
  • availableFunds() returns uint256: returns the amount of ETH or tokens available for the provider

Major benefit would be an ability for subscription provider to monitor the current status of the subscription without using gas (for e.g by executing triggerPayment()). For the subsribee perspective would allow scenarios where 3rd party protocol can monitor and fill the subscription accounts for e.g keeping the funds to pay for next 1 or 2 months

kosecki123 commented Jun 21, 2018

As an extension to @pipermerriam proposal, I think having definitions for functions to return the status of the subscription would be beneficial

  • isFunded() returns bool: returns true if there is currently enough funds (ETH or tokens, depending on implementation) available for provider to collect
  • availableFunds() returns uint256: returns the amount of ETH or tokens available for the provider

Major benefit would be an ability for subscription provider to monitor the current status of the subscription without using gas (for e.g by executing triggerPayment()). For the subsribee perspective would allow scenarios where 3rd party protocol can monitor and fill the subscription accounts for e.g keeping the funds to pay for next 1 or 2 months

@nathantr

This comment has been minimized.

Show comment
Hide comment
@nathantr

nathantr Jun 21, 2018

nathantr commented Jun 21, 2018

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Jul 12, 2018

Update from the working group: We are drafting the EIP at EthereumOpenSubscriptions/standard#8 . All are welcome to contribute. Goal is to have this submitted by early August

owocki commented Jul 12, 2018

Update from the working group: We are drafting the EIP at EthereumOpenSubscriptions/standard#8 . All are welcome to contribute. Goal is to have this submitted by early August

@PaulRBerg

This comment has been minimized.

Show comment
Hide comment
@PaulRBerg

PaulRBerg Jul 17, 2018

Hi everyone,

I'm doing some research on state channels and fully decentralised, recurring payments, so it was pretty cool to read through all the ideas brainstormed here! Definitely a great initiative @owocki.

Static, time-based subscriptions totally make sense, but I want to challenge the underlying assumptions in https://github.com/EthereumOpenSubscriptions regarding dynamic pricing. Why would a company like AWS want to use ERC948 instead of asking the user to pay per unit? That is, when they consume 1MB on S3, they are charged $0.1 (arbitrarily set price). Thanks to Raiden, Liquidity & co, this will be possible in the future once the tech consolidates.

I acknowledge the fact that on state channels one has a balance they cannot go over (although there are proposals to remedy this), while on ERC948 they could be continuously charged from an address, allowing them to top up. This is handy for long-term subscriptions.

However, given low mental transaction costs, I posit that the advantages of pay-per-unit outweigh the disadvantages of billing at the end of the month.

PaulRBerg commented Jul 17, 2018

Hi everyone,

I'm doing some research on state channels and fully decentralised, recurring payments, so it was pretty cool to read through all the ideas brainstormed here! Definitely a great initiative @owocki.

Static, time-based subscriptions totally make sense, but I want to challenge the underlying assumptions in https://github.com/EthereumOpenSubscriptions regarding dynamic pricing. Why would a company like AWS want to use ERC948 instead of asking the user to pay per unit? That is, when they consume 1MB on S3, they are charged $0.1 (arbitrarily set price). Thanks to Raiden, Liquidity & co, this will be possible in the future once the tech consolidates.

I acknowledge the fact that on state channels one has a balance they cannot go over (although there are proposals to remedy this), while on ERC948 they could be continuously charged from an address, allowing them to top up. This is handy for long-term subscriptions.

However, given low mental transaction costs, I posit that the advantages of pay-per-unit outweigh the disadvantages of billing at the end of the month.

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Jul 17, 2018

@PaulRBerg good to meet you. wanna join our weekly call (thursday mornings) and nerd out about this?

owocki commented Jul 17, 2018

@PaulRBerg good to meet you. wanna join our weekly call (thursday mornings) and nerd out about this?

@PaulRBerg

This comment has been minimized.

Show comment
Hide comment
@PaulRBerg

PaulRBerg Jul 17, 2018

Sure thing! Emailed you now.

PaulRBerg commented Jul 17, 2018

Sure thing! Emailed you now.

@Josephrp

This comment has been minimized.

Show comment
Hide comment
@Josephrp

Josephrp Jul 17, 2018

Josephrp commented Jul 17, 2018

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki Jul 17, 2018

yes. contact @androolloyd for the weekly call.

we are all hanging out at gitcoin.co/slack in the #proj-subscriptions channel too

owocki commented Jul 17, 2018

yes. contact @androolloyd for the weekly call.

we are all hanging out at gitcoin.co/slack in the #proj-subscriptions channel too

@PaulRBerg

This comment has been minimized.

Show comment
Hide comment
@PaulRBerg

PaulRBerg Aug 16, 2018

Just published the research I and @mmilton41 have been doing on Chronos, a protocol for continuous, recurring payments. Although it's tangent with the ideas expressed in this chat, the focus is instead on infinitesimally small payment intervals (minutes, hours, rather than months). We mentioned ERC948 and the projects working on it in our draft white paper.

Still many things left to cover (we're using Plasma), but aiming to start coding soon to test our assumptions. Feel free to join the discussion here:

https://ethresear.ch/t/chronos-a-quirky-application-proposal-for-plasma/2928

PaulRBerg commented Aug 16, 2018

Just published the research I and @mmilton41 have been doing on Chronos, a protocol for continuous, recurring payments. Although it's tangent with the ideas expressed in this chat, the focus is instead on infinitesimally small payment intervals (minutes, hours, rather than months). We mentioned ERC948 and the projects working on it in our draft white paper.

Still many things left to cover (we're using Plasma), but aiming to start coding soon to test our assumptions. Feel free to join the discussion here:

https://ethresear.ch/t/chronos-a-quirky-application-proposal-for-plasma/2928

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment