---
# System prepended metadata

title: Custom SuperToken

---

# Custom SuperToken

First familiarize yourself with the possible [types of SuperTokens](https://docs.superfluid.finance/superfluid/developers/super-tokens/types-of-super-tokens).
Once you decided you want a Custom SuperToken, there's a few more choices to be made regarding Upgradability and Governance.

SuperTokens are by default upgradable. While it's in principle possible to create non-upgradable SuperTokens, that's currently not recommended.  
That's because SuperTokens are tightly integrated with the set of Superfluid framework contracts. Those are still evolving through upgrades, and occasionally those upgrades require changes to the SuperToken logic too.
Keeping the logic of SuperTokens in sync with each other also helps keeping them fully compatible with the off-chain tooling.

When implementing a Custom SuperToken, the recommended technical design depends on a few choices, mainly regarding required Modifications, Upgradability and Governance.

## Modifications

The Superfluid contracts include 2 types of canonical SuperToken implementations:
* ERC20 wrappers: deploy a stock UUPSProxy contract pointing to the canonical SuperToken implementation
* SETHProxy: extends UUPSProxy with functionality for upgrading/downgrading  from/to the the native asset (ETH, MATIC, ...), points to the canonical SuperToken implementation

[SETHProxy](https://github.com/superfluid-finance/protocol-monorepo/blob/dev/packages/ethereum-contracts/contracts/tokens/SETH.sol) is an example for a custom SuperToken which adds functionality.  

Example for **added functionality** in SETHProxy:
```
    function upgradeByETH() external override payable {
        ISuperToken(address(this)).selfMint(msg.sender, msg.value, new bytes(0));
        emit TokenUpgraded(msg.sender, msg.value);
    }
```
This does an external call to `selfMint`, which is an external method of SuperToken provided specifically for the use case of extending functionality in Custom SuperTokens.  
It needs to be an external call (forced by the syntax `ISuperToken(address(this)).<method>`) in order to route the call through the fallback function of the proxy, which triggers a delegateCall to the implementation. The "self" methods (alongside `selfMint`, there's also `selfBurn`, `selfTransferFrom` and `selfApprove`) can be invoked only by the token contract itself (`msg.sender == address(this)` needs to be true). 
This is the case when invoking the method from a proxy via delegateCall, because in that context both `msg.sender` and `address(this)` point to the proxy's address.

It's also possible to implement **changed behaviour** using this pattern.
You could for example add a transfer fee by implementing `transfer` and `transferFrom` in the proxy and use `selfTransferFrom` like this:
```
    function transferFrom(address holder, address recipient, uint256 amount) public returns (bool) {
        // transfer to the receiver
        ISuperToken(address(this)).selfTransferFrom(holder, msg.sender, recipient, amount);

        // transfer the fee
        ISuperToken(address(this)).selfTransferFrom(holder, msg.sender, feeRecipient, feePerTx);
        
        return true; // returns true if it didn't revert
    }
    
    function transfer(address recipient, uint256 amount) public returns (bool) {
        return transferFrom(msg.sender, recipient, amount);
    }
```

In this case, the implementation of `transfer` and `transferFrom` in the proxy contract shadows the one in the implementation contract. This basically intercepts their invocations (prevents them being handled by the fallback function which would route the calls to the implementation contract).

Many potential modifications can be implemented using the same pattern.  

While it's in principle possible to implement arbitrary behaviour changes (because ultimately the Proxy contract can intercept any call and has full control over what logic it executes in respone), it's recommended to rely on the canonical SuperToken implementation as much as possible in order to avoid the maintenance cost of keeping Custom SuperTokens compatible with the Superfluid framework.


## Upgradability

Upgradability of SuperToken contracts is usually implemented using the [UUPSProxy contract](https://github.com/superfluid-finance/protocol-monorepo/blob/dev/packages/ethereum-contracts/contracts/upgradability/UUPSProxy.sol). You can find a good explanation of the UUPSProxy pattern [here](https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent-vs-uups).

The usage of a Proxy for SuperToken contracts not only makes them upgradable, but also helps reducing deployment costs, because the (rather large) logic contract can be shared by many (rather small) Proxy contracts.

A caveat to be considered in the context of Custom SuperTokens is this:  
The custom logic placed in the Proxy contract will NOT be upgradable.
That is, in the example above which adds a fee to transfers, it would not be possible to later change the behaviour to for example add another transfer to a second fee receiver. Such possible future behaviour changes need to be covered from the start e.g. by making it configurable by an admin.

If upgradability of the custom logic is a MUST, there's a few more involved options to achieve that:
a) Instead of extending the Proxy, extend the SuperToken contract and deploy a custom version of it. This means the SuperToken will not be *managed* by Superfluid governance (upgraded to the latest canonical logic). There's also constraints to how much logic can be added (contract size limit) since the SuperToken implementation is already quite complex.
Extending the SuperToken contract is facilitated by its public interface methods being `virtual`.
b) Nested proxies: You could deploy a stock proxy which points to an intermediate proxy with your custom logic and routes everything else to the canonical SuperToken implementation contract.
c) Custom routing: You could implement a Proxy contract with additional logic which intercepts calls to a few methods and routes them to a secondary implementation contract, where you put your custom, now upgradable logic. This would however not be standards compliant and thus lack ecosystem support (e.g. not be understood by Explorers)
d) Use the [Diamond Pattern](https://eips.ethereum.org/EIPS/eip-2535). This is similar to the previous option, but following an opinionated terminology  specified in an EIP.

## Governance

SuperTokens are by default *managed* by Superfluid governance. That means the same account having exlusive permission to upgrade Superfluid framework contracts also has exclusive permission to update the logic of managed SuperToken contracts.  
While this can be convenient (least maintenance cost), you may not want to delegate governance over your SuperToken's upgradability.

Currently the only way to retain upgradability governance is to deploy a copy of the SuperToken contract with changed `updateCode` implementation.
You can find an example for such an implementation [here](https://github.com/superfluid-finance/custom-supertokens/blob/bridged-supertoken/contracts/alternative-logic/BridgedSuperToken.sol).

It's technically possible to change the canonical implementation such that the upgrade admin can be specified at deploy time.
If you are interested in creating such a token, please let us know and we may implement such a change in order to make it easier for you.