🦾 Super Apps

Manage Flows and IDAs using a smart contract

A Super App can "manage" agreements and respond to changes. This is where you can write your own custom logic/behavior. In this section we will deploy a new Super App using Remix.

So what will our app do? Our app will accept incoming CFA flows, and use some internal logic to determine where to redirect it. The reciever of all the incoming flows will be decided by whoever owns a ERC721 Non-fungible Token (NFT).

If the NFT is transferred to a new owner, all token flows are redirected to the new owner.

We will call the app Holy Grail, since whoever is in possession of the NFT is blessed with great power.

A chalice is handed to another person (https://unsplash.com/@reskp)


If you'd prefer to listen and code along, I've made a video version of this tutorial section:



Before starting this tutorial you should:


Click the link to load the contracts in Remix:

Once it loads, you should see TradeableCashflow.sol in the editor window.

In the file explorer, click to expand gist "2d2c1..." to view both contracts. TradeableCashflow.sol is our main contract, which inherits RedirectAll from the local file, and the ERC721 contract from the Open Zeppelin Github repo.

The two main concepts of TradeableCashflow.sol are:

  1. Create a new ERC721 contract, and mint a single NFT to be the Holy Grail

  2. Whenever the NFT is transferred, the _beforeTokenTransfer() hook calls _changeReceiver() which will redirect the incoming flows.

Calling Agreements

In order for our app to redirect flows, it must be able to call the Superfluid Agreements.

Let's look at what _changeReceiver() does in the contract RedirectAll.sol. The first step is to delete the current flow from the Super App to the current reciever.

// @dev Change the Receiver of the total flow
function _changeReceiver( address newReceiver ) internal {
// @dev delete flow to old receiver
new bytes(0)

This is the first time we are introducing examples of how to interact with the Framework contracts directly. Don't worry about understanding every part right now, you can just skim to get an idea.

Here's how the same code would look if we were using the@superfluid-finance/js-sdk to perform the same action:

await flow({recipient: currentRecipient, flowRate: "0" });

In the next part of _changeReveiver(), the Super App starts a new flow to the new reciever, or new NFT owner:

// @dev create flow to new receiver
_cfa.getNetFlow(_acceptedToken, address(this)),
new bytes(0)
// @dev set global receiver to new receiver
_receiver = newReceiver;
emit ReceiverChanged(_receiver);

Again for comparison, here is how it would look if we used the superfluid-finance/js-sdk instead:

// Get the new incoming flow rate
const newFlowRate = await sf.cfa.getNetFlow({
superToken: _acceptedToken,
account: myContract.address
// Start a flow to the new recipient
await flow({recipient: newRecipient, flowRate: newFlowRate });
// Reassign the recipient to the newRecipient
currentRecipient = newRecipient

This is how we can call an Agreement to start a flow in a contract. But what about reacting to incoming flows automatically? To respond to changes in an Agreement, we need to use Super App callbacks.


Super Apps can respond to changes in Agreements using callbacks. This can be done without needing to call a function in your contract.

When anyone creates a new flow to the Holy Grail contract, we need to "catch" this transaction, and automatically redirect the flow to the receiver.

Around line 170 in RedirectAll.sol we can start to see all the callbacks. The fist one is afterAgreementCreated(). This function is called any time a new agreement is created which involves the SuperApp.

function afterAgreementCreated(
ISuperToken _superToken,
address _agreementClass,
bytes32, // _agreementId,
bytes calldata /*_agreementData*/,
bytes calldata ,// _cbdata,
bytes calldata _ctx
external override
onlyExpected(_superToken, _agreementClass)
returns (bytes memory newCtx)
return _updateOutflow(_ctx);

Using the modifier onlyExpected allows use to only execute this when the agreement is a Constant Flow Agreement, and the token address matches the _superToken .

Assuming all the checks pass, then we can trigger _updateOutFlow which combines the new incoming flow and creates the new flow

Now that you understand the two main components of a Super App, its time to deploy it!


Switch back to TradeableCashflow.sol in the editor window.

Now in the Compiler tab, make sure you're using compiler version 0.7.0 and hit "compile".

Once compilation is complete, switch to the "Deploy and Run Transactions" tab. Select Environment β€œInjected Web3”, and in your wallet switch to Goerli test network.

Next select the TradeableCashflow contract to deploy, and use the following parameters to deploy:




(Use your address)


Holy Grail











This will deploy the Holy Grail contract, mint a single NFT, and transfer it to the owner. Once the transaction is confirmed, copy the address of the deployed contract.



Now comes the magic part. Since we used callbacks in our Super App, we can create a new flow from the Superfluid Dashboard. Our Super App will react to this automatically.

Using the address you copied in the previous step, start a new flow using fDAIx (shown as DAIx in the Dashboard) to your Super App.

After the transaction is confirmed, you will see both an incoming and outgoing flow from the same address. This is because you are the owner of the NFT, so you're effectively streaming to yourself via the Super App.

Now let's transfer the Holy Grail NFT to someone else using transferFrom(). Since there is only a single NFT, the tokenId will be always be 1.

Upon transfer, all incoming flows will be re-directed to the new NFT holder. You can verify this by logging into the Superfluid Dashboard using the receiver's account.

Excellent! Now you know how a Super App works. In the next section we will discuss deploying the Superfluid Framework so you can easily test your own Super App using a local blockchain.