eip: 1620
title: ERC-1620 Money Streaming
author: Paul Razvan Berg (@PaulRBerg) <[email protected]>
discussions-to: https://github.com/ethereum/EIPs/issues/1620
status: Final
type: Standards Track
category: ERC
created: 2018-11-24
requires: 20
We define money streaming as continuous payments over a finite period of time. Block timestamps are used as an on-chain proxy for time.
The following describes a standard whereby time is measured using block timestamps and streams are mappings in a master contract.
- Developer sets up a money streaming contract.
- A payer, henceforth referred to as sender, can create a stream by depositing funds in the contract and choosing a streaming duration.
- A payee, henceforth referred to as recipient, can withdraw money from the stream based on its continuous solvency. That is,
payment * (current block timestamp - starting block timestamp)
. - The stream can be terminated by either the sender or the recipient.
- If the stream ended and has not been terminated, the recipient is entitled to withdraw all the remaining balance.
This standardised interface takes a stab at changing the way we think about trust in financial contracts. Thanks to blockchains, payments need not be sent in lumps (as with monthly salaries), as there is less overhead in pay-as-you-go. Money as a function of time would better align incentives in a host of scenarios.
This is just a preliminary list of use cases. There are other interesting ideas left to explore, such as time-dependent disincetivisation, but, for brevity, we have not included them here.
- Salaries
- Insurance
- Subscriptions
- Consultancies
- Rent
- Parking
- Lending
Sablier is a champion project for this ERC. It is what we call the protocol for real-time finance.
The structure of a stream should be as follows:
Stream
deposit
: the amount of money to be streamedratePerSecond
: the number of tokens allocated each second to the recipientremainingBalance
: the left in the streamstartTime
: the unix timestamp for when the stream startsstopTime
: the unix timestamp for when the stream stopsrecipient
: the address towards which the money is streamedsender
: the address of the party funding the streamtokenAddress
: the ERC20 token to use as streaming currencyisEntity
: indicates whether the stream exists or not
struct Stream {
uint256 deposit;
uint256 ratePerSecond;
uint256 remainingBalance;
uint256 startTime;
uint256 stopTime;
address recipient;
address sender;
address tokenAddress;
bool isEntity;
}
Returns the stream object with all its properties.
function getStream(uint256 streamId) view returns (address sender, address recipient, uint256 deposit, address token, uint256 startTime, uint256 stopTime, uint256 remainingBalance, uint256 ratePerSecond)
Returns the real-time balance of the account with address who
.
function balanceOf(uint256 streamId, address who) view returns (uint256 balance)
Creates a new stream funded by msg.sender
and paid towards recipient
. MUST throw if recipient
is the zero address, the contract itself or the caller themselves. MUST throw if startTime
is before the current block timestamp. MUST throw if stopTime
is before startTime
. MUST throw if deposit
is not a multiple of the time delta. MUST throw if the contract is not allowed to transfer enough tokens.
Triggers Event: CreateStream
function createStream(address recipient, address deposit, address tokenAddress, uint256 startTime, uint256 stopTime) returns (uint256 streamId)
Withdraws from the contract to the recipient's account.
MUST throw if the caller is not the sender or the recipient. MUST throw if amount
exceeds the available balance.
Triggers Event: WithdrawFromStream
function withdrawFromStream(uint256 streamId, uint256 amount) returns (bool success)
Cancels the stream and transfers the tokens back on a pro rata basis.
MUST throw if the caller is not the sender or the recipient.
Triggers Event: CancelStream
function cancelStream(uint256 streamId) returns (bool success)
MUST be triggered when createStream
is successfully called.
event CreateStream(uint256 indexed streamId, address indexed sender, address indexed recipient, uint256 deposit, address tokenAddress, uint256 startTime, uint256 stopTime);
MUST be triggered when withdrawFromStream
is successfully called.
event WithdrawFromStream(uint256 indexed streamId, address indexed recipient, uint256 amount);
MUST be triggered when cancelStream
is successfully called.
event CancelStream(uint256 indexed streamId, address indexed sender, address indexed recipient, uint256 senderBalance, uint256 recipientBalance);
This specification is designed to serve as an entry point to the quirky concept of money as a function of time. Several other designs, including payment channels have been considered, but they were deemed dense in assumptions unnecessary for an initial draft.
Block timestamps are a reasonably secure proxy for time on the blockchain. Although miners handle them, there are game-theoretical incentives to not provide malicious timestamps. Read this thread on StackExchange for more details.
The only dangerous scenario we can think of is when ERC-1620 derived implementations end up making up a significant share of the volume of money transferred on Ethereum. It is possible, although unlikely, that some stream recipients will have an incentive to coax miners in bumping the block timestamps for them to profit. But we posit the payoff (a few seconds or minutes times the payment rate) will not be high enough for this kind of attack to be worth it.
- Sablier Launch Thread
- Introducing Sablier: Continuous Salaries on Ethereum
- Chronos Protocol Ethresear.ch Plasma Proposal
- Flipper: Streaming Salaries @ CryptoLife Hackathon
- SICOs or Streamed ICOs
- RICOs or Reversible ICOs
- Andreas Antonopoulos' Keynote on Bitcoin, Lightning and Money Streaming
Copyright and related rights waived via CC0.