Skip to content

nounsDAO/streamer

Repository files navigation

Streamer by Nouns DAO

Motivation

This project solves the problem of allowing payers of token streams to create streams and fund them after the fact, i.e. first create the stream, then fund it later when funds are available.

For example, Nouns DAO can use Token Buyer with Streamer and create proposals that:

  1. Create a Stream
  2. Ask TokenBuyer's Payer contract to send tokens to the newly created Stream when it has the funds
  3. TokenBuyer acuiqres the funds, sends them to Payer, Payer funds the Stream
  4. The Stream's recipient can start withdrawing funds

Contracts

  • StreamFactory

    • Creates new Streams using minimal clones
    • Supports predicting new Stream contract addresses, making it easier to compose DAO proposals, since a proposal author can know the address of the Stream the proposal will create before it's created
  • Stream

    • Supports custom start and end timestamps
    • Does not enforce upfront funding, making it usable for DAOs and other payers that acquire payment tokens post Stream creation

How to run tests

To run smart contract tests, make sure you have Foundry installed, then run:

forge install
forge test

How to deploy and manually test locally

Run Foundry's local node:

anvil

Copy one of anvil's test account's address and private key, to use in commands below.

Deploy StreamFactory:

forge script script/DeployStreamFactory.s.sol --rpc-url http://127.0.0.1:8545 --broadcast --sender <anvil test account address> --private-key <anvil test account private key>

Deploy MockToken, which you can use to mint tokens to your test Streams:

forge script script/DeployMockToken.s.sol --rpc-url http://127.0.0.1:8545 --broadcast --sender <anvil test account address> --private-key <anvil test account private key>

Go to ./broadcast/DeployStreamFactory.s.sol/31337/run-latest.json and copy the value of contractAddress for StreamFactory. Go to ./broadcast/DeployMockToken.s.sol/31337/run-latest.json and copy the value of contractAddress for ERC20Mock.

Copy another anvil test account and private key to use as your stream recipient.

If you want to create a stream that starts or ends in the future, you can use foundry.toml to override anvil's first block timestamp, or run cast block latest and copy the timestamp of the current block as a starting point to your stream.

Simulate stream creation:

cast call --rpc-url http://127.0.0.1:8545  --private-key <your first anvil test account private key> <your StreamFactory address> "createStream(address,uint256,address,uint256,uint256)" <your second test account, the recipient of the stream> <the token amount to stream, e.g. 1000> <your ERC20Mock contract address> <stream start timestamp, e.g. as taken from running cast block latest above> <stream end timestamp, e.g. start time + 1000 to make it predictable>

The output will look something like:

0x00000000000000000000000033f456c89902746ffed70041f8bc8672e3a171fd

This is the expected new stream address, you just need to trim it down a bit, in this case to be: 0x33f456c89902746ffed70041f8bc8672e3a171fd.

Execute stream creation using the same inputs, by running the same command as above, only using cast send instead of cast call.

To make sure you're stream has been created, get the recipient's balance; it should be greater than zero:

cast call --rpc-url http://127.0.0.1:8545  --private-key <a test account private key> <stream contract address> "balanceOf(address)(uint256)" <stream recipient address>

To withdraw, you'll need to mint tokens to fund the stream, then call withdraw using the recipient account:

cast send --rpc-url http://127.0.0.1:8545  --private-key <a test account private key> <the ERC20Mock contract address> "mint(address,uint256)" <the stream contract address> <the stream amount, e.g. 1000>

cast send --rpc-url http://127.0.0.1:8545  --private-key <the payer or recipient account private key> <the stream contract address> "withdraw(uint256)" <the withdrawal amount, should not exceed recipient current balance>

Local subgraph setup

In ./subgraph/networks.json, make sure StreamFactory's address matches the one you recently deployed.

Spin up your local node: (you need Docker installed and running in the background)

yarn local-node

Then run:

yarn
yarn codegen
yarn build:local
yarn create:local
yarn deploy:local

You should now be able to query the subgraph and see your recently created streams and any withdrawals and cancellation events related to it. You can use Postman or any other HTTP request tool, send a POST request to http://localhost:8000/subgraphs/name/streamer with a GraphQL query like:

query {
    streams (limit: 10) {
        id
        createdAt
        createdBy
        payer
        recipient
        tokenAmount
        tokenAddress
        startTime
        stopTime
        withdrawals {
            id
            withdrawnAt
            executedBy
            amount
        }
        cancellations {
            id
            cancelledAt
            cancelledBy
            payerBalance
            recipientBalance
        }
    }
}

How to deploy to Sepolia

Copy ./env.example to ./.env and set your values.

Deploy StreamFactory:

forge script script/DeployStreamFactory.s.sol --verify -vvvvv --rpc-url https://sepolia.infura.io/v3/<infura API key> --broadcast --sender <your deployer account address> -i 1

Deploy ERC20Mock:

forge script script/DeployMockToken.s.sol --verify -vvvvv --rpc-url https://sepolia.infura.io/v3/<infura API key> --broadcast --sender <your deployer account address> -i 1

Subgraph: run a local node indexing Sepolia

At the time of writing, the hosted service does not support Sepolia, but we can still run a local node.

In ./subgraph/networks.json, make sure StreamFactory's address matches the most recent deployment you want to use; you might find it under ./broadcast/DeployStreamFactory.s.sol/11155111/run-latest.json.

Copy ./subgraph/.env.example to ./subgraph/.env and set network name and RPC env vars - these are used in docker-compose.yml.

Spin up your local node: (you need Docker installed and running in the background)

yarn local-node

Then run:

yarn
yarn codegen
yarn build:sepolia
yarn create:sepolia
yarn deploy:sepolia

Querying works as outlined above for local testing.

Latest deployment

Mainnet

Contract Address
StreamFactory 0x0fd206FC7A7dBcD5661157eDCb1FFDD0D02A61ff
Stream 0x0b9dFf1aba32A9fa95011C7f097ec672F689038F

Goerli

Contract Address
StreamFactory 0xc08a287eCB16CeD801f28Bb011924f7DE5Cc53a3
Stream 0x20ffE6b3b08f5009788812583D42C5b42bf44447

About

ERC20 Token Streaming Protocol

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published