# Super Apps in Depth

### **What is a Super App?**

Super Apps are smart contracts that are registered with the Superfluid Protocol allowing them to **react to Super Agreements** (like money streams). If you're familiar with ERC777 hooks, they're like those but for Super Agreements.

![The Tradeable Cashflow NFT](https://422548309-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MKEcOOf_qoYMObicyRu%2Fuploads%2Fgit-blob-b568c2285e58390587a3cffa0f834c6fac44b283%2Fimage%20\(29\)%20\(1\).png?alt=media)

For example, upon the [tradeable cashflow NFT contract](https://github.com/superfluid-finance/super-examples/tree/c784d239557d6fb5e56a2c8951ac4353256d611d/projects/tradeable-cashflow) receiving a stream, special callbacks functions within the Super App are triggered which automatically open up a new stream from the NFT contract to the owner of the NFT. The contract 'listens' for a call to a Superfluid super agreement contract (the Constant Flow Agreement contract), and runs a single callback function in response to the following 3 actions:

1. A flow is opened with the Super App as the `receiver`
2. A flow is updated which has the Super App as the `receiver`
3. A flow is closed by the Super App's counter party (i.e. if either the *sender* of a flow into the Super app or the *recipient* of a flow from the Super App deleted the flow, a callback will be run). As of today, this is only relevant for the case of canceled flows.

When a stream is created into a Super App (this will make the Super App the `receiver` ), the `beforeAgreementCreated` and the `afterAgreementCreated` callback may be run. These callbacks can execute any arbitrary logic, as long as this logic fits within the rules of standard smart contract development and the rules of Super Apps (which are explained further later on in this section).

In the case of the tradeable cashflow contract, the logic we include inside of the `afterAgreementCreated` callback will open up a money stream from the app to the NFT's owner in an amount that is equal to the `flowRate` into the app.

Super Apps like the tradeable cashflow example keep their callback logic simple, while others get more advanced and leverage items like `userData` for additional functionality.

Some of the most interesting projects in our ecosystem, such as Ricochet Exchange, make heavy use of Super App callbacks.

### Super App Configuration

For a Super App to be able to use callbacks, it must first be 'registered' with the protocol. This is done using a pattern similar to the [ERC1820 registry system](https://eips.ethereum.org/EIPS/eip-1820).

To register a Super App, you need to add the following code to your Super App's constructor:

```
// by default, all 6 callbacks defined in the ISuperApp interface
// are forwarded to a SuperApp.
// If you inherit from SuperAppBase, there's a default implementation
// for each callback which will revert.
// Developers will want to avoid reverting in Super App callbacks, 
// In particular, you want to avoid reverting within the termination callback
// (see rules below regarding the termination callback for more info)
// you need to make sure only those actually implemented (overridden)
// are ever invoked. That's achieved by setting the _NOOP flag for those
// callbacks which you don't need and didn't implement.
uint256 configWord =
            SuperAppDefinitions.APP_LEVEL_FINAL |
            SuperAppDefinitions.BEFORE_AGREEMENT_CREATED_NOOP |
            SuperAppDefinitions.BEFORE_AGREEMENT_UPDATED_NOOP |
            SuperAppDefinitions.BEFORE_AGREEMENT_TERMINATED_NOOP;

// can be an empty string in dev or testnet deployments
string memory registrationKey = "";

        _host.registerAppWithKey(configWord, registrationKey);
```

Running `_host.registerAppWithKey` and passing in the `configWord` will enable your Super App to be registered within the Superfluid host contract's Super App manifest. This will allow it to be managed under basic Superfluid governance parameters and ensure that callbacks are run as intended.

The `APP_LEVEL_FINAL` must be set as seen above for now. This parameter refers to which (and how many) callbacks will be run within a hypothetical chain of Super Apps.&#x20;

For example, if a user calls a Super app, then that app calls another Super App, do the Super App callbacks run in both contracts, the second contract in the chain of events, or the first contract in the chain of events? The answer to this question, as of Q4 2021, is that the callbacks are run within the **first app only.**&#x20;

The `_NOOP` (pronounced 'no-op') designations are also important as they allow you to specify which callbacks you'd like to use in your Super App. Callbacks can run **before** and/or **after** an agreement function runs.&#x20;

If you inherit from the [SuperAppBase](https://github.com/superfluid-finance/protocol-monorepo/blob/dev/packages/ethereum-contracts/contracts/apps/SuperAppBase.sol) contract, there's a default implementation for each callback which will revert. It's critical to ensure you have a well-tested implementation for each callback, and that you use the `_NOOP` pattern to prevent the callbacks you *don't* wish to use from running. In the case of an app that only uses the `afterAgreement` callbacks, you'll want to add the `_NOOP` flag to each callback you won't be using - in this case the `beforeAgreement` callbacks. This can be done like so within your `configWord` variable.

```jsx
SuperAppDefinitions.BEFORE_AGREEMENT_CREATED_NOOP |
SuperAppDefinitions.BEFORE_AGREEMENT_UPDATED_NOOP |
SuperAppDefinitions.BEFORE_AGREEMENT_TERMINATED_NOOP;
```

Finally, you can register your app using `_host.registerAppWithKey(configWord)` or with `_host.registerAppByFactory(app, configWord)`.

You can do this freely on testnets, but on mainnets pre-approval of Super Apps is needed for now.\
Navigate to [this guide](https://github.com/superfluid-finance/protocol-monorepo/wiki/Super-App-White-listing-Guide) in order to find out how to get that done.

### Super App CFA Buffers&#x20;

When a user first creates a Superfluid stream, the protocol will take an up front [buffer](https://superfluid.gitbook.io/superfluid/sentinels/liquidations-and-toga) to ensure the protocol's security. These deposits are sized as follows:

* On testnets, when the flow is being sent to a recipient that is *not* a Super App, this amount is 1hr x the `flowRate`
* On testnets, when the flow is being sent to a recipient that *is* a Super App, the deposit amount can be up to 2hrs x the `flowRate`
* On mainnet, when the flow is being sent to a recipient that is *not* a Super App, the deposit amount is 4hrs x the `flowRate`
* On mainnet, when the flow is being sent to a recipient that *is* a Super App, the deposit can be up to 8hrs x the `flowRate` (note that this is approximate)

**Why can the deposit by up to \~2x when sending a stream to a Super App?**

Because Super Apps are designed to enable programmable cashflows, the protocol needs to ensure that Super Apps don't execute logic that could impact the protocol's security. The caller of the stream being sent to the super app is essentially *covering the deposit* of the Super App.

This higher deposit provides an extra incentive for the protocol to ensure that users sending streams into super apps maintain a balance > 0.&#x20;

### Super App Callbacks

Super App callbacks are run when a Super App is on the receiving end of a callAgreement call (i.e. an operation which executes logic in one of the existing agreement contracts, such as the IDA or CFA)

**When Will Super App Callbacks Run?**

In the case of the constant flow agreement, Super App callbacks will run when&#x20;

* a stream is created where the app is the `receiver` of the stream.
* a stream is updated where the app is the `receiver` of the stream. &#x20;
* a stream is deleted by a user or contract that is external to the Super App.&#x20;

Note that in the third case, a stream may be deleted by *either the sender or the receiver* of that stream. This means that the `beforeAgreementTerminated` or `afterAgreementTerminated` callback will run if a stream that was being sent into the Super App was deleted by the sender, or if a stream being sent from the Super App to another address was deleted by the receiver of that stream.

**Who is Calling the Super App Callback?**

Callbacks are called entirely on chain by the Superfluid protocol in response to events. Each time an action is taken inside of the Constant Flow Agreement contract, the protocol will check the Super App registry to determine whether or not the stream will be sent to a Super App (or if the stream being deleted involves a Super App in the event of deletion). If it doesn't involve a Super App, there are no callbacks to run, so the stream is created, updated, or deleted without any other operation.&#x20;

However, if the protocol finds that the stream indeed does involve a Super App after a check to the Superfluid Super App manifest, it will call the necessary callback(s).

#### The Anatomy of Super App Callbacks:

```
function beforeAgreementCreated(
        ISuperToken /*superToken*/,
        address /*agreementClass*/,
        bytes32 /*agreementId*/,
        bytes calldata /*agreementData*/,
        bytes calldata /*ctx*/
    )
        external
        view
        virtual
        override
        returns (bytes memory /*cbdata*/)
    {
        revert("Unsupported callback - Before Agreement Created");
    }
```

```
    function afterAgreementCreated(
        ISuperToken /*superToken*/,
        address /*agreementClass*/,
        bytes32 /*agreementId*/,
        bytes calldata /*agreementData*/,
        bytes calldata /*cbdata*/,
        bytes calldata /*ctx*/
    )
        external
        virtual
        override
        returns (bytes memory /*newCtx*/)
    {
        revert("Unsupported callback - After Agreement Created");
    }
```

A `beforeAgreement` callback will be run before the call to the agreement contract will be run. For example, if there is logic inside of the `beforeAgreementCreated` callback within of a Super App, and a user opens a stream into that Super App contract, the logic inside of `beforeAgreementCreated` will run before the stream is created.

Similarly, an `afterAgreement` callback will be run after the call to the agreement contract is run. For example, if there is logic inside of the `afterAgreementCreated` callback within a Super App, and a user opens a stream into that Super App contract, the logic inside of `afterAgreementCreated` will run after the stream is created.

One additional thing to note about the `beforeAgreement` callbacks is that they are `view` functions. So, if you want to, for example, save a variable to state in response to something that happens in the `beforeAgreement` callback, you should do the following:

1. Return the data that you want to save inside the `beforeAgreement` callback (this returned value will be passed to the `afterAgreement` callback as `cbdata`, which we explain below)
2. Save the variable to state inside of the `afterAgreement` callback
3. Make sure that you have an implementation for both the `beforeAgreement` and `afterAgreement` callbacks

**Breaking Down Each Variable**

**`ISuperToken`** - the protocol will pass the Super Token that's being used in the call to the constant flow agreement contract here.

**`address`** - this will be the address of the Constant Flow Agreement contract on the network you're interacting with. You can find more details around these networks inside of the Superfluid network directory.

**`agreementId`** - a bytes32 value that is a hash of the sender and receiver's address of the flow that was created, updated, or deleted.

**`agreementData`** - the address of the sender and receiver of the flow that was created, updated, or deleted - encoded using solidity's `abi.encode()` built in function

**`cbdata` -** this contains data that was returned by the `beforeAgreement` callback *if* it was run prior to the calling of `afterAgreement` callback. **Note**: this is only passed to the `afterAgreement` callback

**`ctx`** - this contains data about the call to the Constant Flow Agreement contract itself. 'Ctx' is short for 'context' and is explained in depth inside of our tutorial on userData (which you can access inside of the `ctx` value).

### Super App Rules (Jail System)

Super Apps are a powerful concept within the Superfluid ecosystem. They allow for new levels of creativity - specifically related to *programmable cash flows.*

However, there are specific rules that have been encoded into the protocol which SuperApps must abide by. Super App rules should be obeyed at all cost by developers, or they risk their contract being jailed by the protocol.&#x20;

What does it mean for an app to be 'jailed' exactly? We apply the term `jailed` to refer to a Super App that failed to comply with the set of rules encoded into the Superfluid framework. This does **not** mean that someone on the Superfluid core team is exerting arbitrary control over your Super Apps.

These rules have been written into the protocol at the software level, and are simply designed to place basic security guardrails on Super Apps. Complex systems in our industry have constraints, and you can think of Super App rules as an extension of those constraints that apply to this subset of the protocol.

> 💡 These rules are a set of restrictions placed on Super Apps that are built into the protocol to protect users. However, these rules are not comprehensive and cannot guarantee that a SuperApp will be 100% safe. Each user should review the Super Apps they are interacting with, and developers should take care to write secure, well-tested Super App code.

#### **Here's an overview of each rule:**

1\) Super Apps cannot revert in the termination callback (`afterAgreementTerminated()`)

* Use the **trycatch** pattern if performing an action which interacts with other contracts inside of the callback. Doing things like transferring tokens without using the **trycatch** pattern is dangerous and should be avoided.
* Double check internal logic to find **any revert possibility in this callback.**

2\) Super Apps can't became insolvent.

* Check if any interaction can lead to **insolvency** situation.
* What is an **insolvency** situation? This occurs when a Super App tries to continue sending funds that it no longer has. Its super token balance must stay > 0 at minimum. You can learn more about liquidation & solvency [in our section on this topic.](https://docs.superfluid.finance/superfluid/docs/liquidations-and-toga)

3\) Gas limit operations within the termination callback (`afterAgreementTerminated()`)

* There is a limit of gas limit send in a callback function (*3000000 gas units)*
* If the Super App reverts on terminations calls because of an *out-of-gas* error, it will be jailed.
* For legitimate cases where the app reverts for *out-of-gas* (below the gas limit), the Super App is subject to user decision to send a new transaction with more gas. If the app still reverts, it will be jailed.
* To protect against these cases, **don't create Super Apps that require too much gas within the termination callback**.

4\) Incorrect ctx (short for **context)** data within the termination callback

* **Any attempt to tamper with the value of `ctx`** or failing to give the right **`ctx`** will result in a Jailed App.
* Any time a protocol function returns a `ctx`, that `ctx` should be passed to the next called function. It will repeat this process even in the return of the callback itself.
* For more information on `ctx` and how it works you can check out our tutorial on userData.

#### Checking for Jailing

You can check if a Super App is jailed by calling `isAppJailed` on the Superfluid Host contract on the appropriate network and passing in the Super App address in concern. You can conveniently call this in the Read Contract section on Etherscan for our Host contracts which are all verified (for example, see function #19 on [Polygonscan](https://polygonscan.com/address/0x3E14dC1b13c488a8d5D310918780c983bD5982E7#readProxyContract)). Host addresses can be found in our [Protocol directory](https://console.superfluid.finance/matic/protocol).

Also, when a Super App is jailed, it emits a `Jail` event (see [here](https://github.com/superfluid-finance/protocol-monorepo/blob/0594cdc01ee13780f715f2c38c1a356830d67721/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol#L445C5-L445C55)). So, you can query all Jail events through our subgraph. The below query returns the addresses of all the jailed Super Apps on a network. Try running it in our Console's [subgraph sandbox](https://console.superfluid.finance/subgraph).

```
query JailedAppsQuery {
  jailEvents {
    app
  }
}
```
