A Constant Flow Agreement (CFA) is a transfer of value from a sender
to a receiver
at a constant flowRate
measured in amount per second.
Here is overview of the CFA contract. Did someone say CRUD ?
contract IConstantFlowAgreementV1 is ISuperAgreement {function createFlow( ...function updateFlow( ...function deleteFlow( ...}
Seem straightforward enough? Let's go!
Before starting this tutorial you should:
Complete the @superfluid-finance/js-sdk tutorial
Have some goerli ETH and tokens in your wallet from the dashboard https://app.superfluid.finance
Bob has some DAIx, and he wants to send 100 per month to alice.
First let's create a new User
object for Bob.
const bobAddress = "0xbbb...." // address of the sender's walletconst userBob = sf.user({address: bobAddress,token: daix.address // address of the SuperToken});
Now let's have Bob start a flow to Alice
const aliceAddress = "0xaaa...", // address of the receiver's walletawait userBob.flow({recipient: aliceAddress,flowRate: "385802469135802"});
So what is this weird number 385802469135802
? This is the amount of DAIx to transfer per second, which is equivalent to 1000 DAIx per month.
But how can I see these flows? We can call details()
to see a bunch of info about our user:
await userBob.details(); // full object(await userBob.details()).cfa.flows; // detailed flows view
If we call flow()
again, we can edit this stream:
await userBob.flow({recipient: aliceAddress,flowRate: "1000000000000000" // 2592 DAIx per month});
To stop a stream, just pass a 0
value:
userBob.flow({recipient: alice,flowRate: "0"});
Awesome work. You're now ready for the next tutorial 💰 Perform an Instant Distribution
Or you can keep reading to take a deeper dive.
If you want a bit more freedom to customize, you can go one level deeper into our SDK
To achieve this, we will create a Constant Flow Agreement. In this agreement, we define the amount per second and recipient
where DAIx should flow.
await sf.cfa.createFlow({superToken: daix.address,sender: bob,receiver: alice,flowRate: "385802469135802" // 1000 per month});
Here is the breakdown:
A flow is a type of agreement, called a Constant Flow Agreement, CFA in short
We want to send a flow of DAI, so we specify superToken: daix.address
Using the method createFlow()
, we pass the arguments for the DAIx token, sender, receiver, and the amount "385802469135802"
So what is this weird number "385802469135802"? This is the amount of DAIx to transfer per second, which is equivalent to 1000 DAIx per month.
>>> (385802469135802 * 3600 * 24 * 30) / 1e18999.99999999999989 DAIx per month
HUH?! How is bob able to send 1000 DAIx per month if he only has 50 Superfluid enabled DAI? The answer is that the sender isn't required to have the full amount to start a flow. The flow will continue to run as long as he has DAIx.
The flow is now active, so let's check alice and bob's balances to see what changed. Their balances are updated every second, and reflected on-chain at every new block.
(async () => wad4human(await daix.balanceOf(bob)))() >48.36226851851852(async () => wad4human(await daix.balanceOf(alice)))() >0.2546296296296293;
Note: These amounts will not add up to 50 DAIx, due to a refundable deposit.
To get an idea of all Flow activity for bob, we can check his net flow. This will show us the sum of all inflow/outflows for his account.
We can use getNetFlow()
to see the flow we just created.
(await sf.cfa.getNetFlow({superToken: daix.address, account: bob})).toString()> "-385802469135802" # units of wei
Since Bob only has one flow to alice, his net flow is negative. If bob had multiple flows, this would be an easy way to get an overall picture of bob's activity. Let's check it's the right amount:
(-385802469135802 * 3600 * 24 * 30) / 1e18 > -999.9999999999989;
Now lets stop the flow by deleting it. Call deleteFlow()
and select the flow between bob and alice.
sf.cfa.deleteFlow({superToken: daix.address,sender: bob,receiver: alice,by: bob});
Streams are identified by token, sender, and receiver.
The parameter "by" defines who is closing the stream. Streams can be closed by both sender and receiver.
If we check their balances, we'll see that they now add up to 50 since the refundable deposit has been returned.
(await daix.balanceOf(bob)).toString() / 1e18 >"49.04360"(await daix.balanceOf(alice)).toString() / 1e18 >"0.95640";
Great job! You minted some Superfluid-enabled DAI, and created your first Flow.
Next we'll learn about another agreement, called Instant Distribution