superfluid-finance / protocol-monorepo

Superfluid Protocol Monorepo: the specification, implementations, peripherals and development kits.
https://www.superfluid.finance
Other
875 stars 240 forks source link

[SPIKE] ERC-4626 & Super Tokens #1894

Closed d10r closed 6 months ago

d10r commented 8 months ago

What & Why

@vmichalik asking:

Did we find any unintended consequences of making 4626 shares super tokens?

AC

Recommendation / Options

d10r commented 8 months ago

In my investigations, 2 aspects which are relevant for the project triggering it, but which are otherwise independent of each other, were considered:

ERC-4626

ERC-4626 is an extension to ERC-20 which defines a standard interface for the interactions between the representing shares (the tokens managed by this contract itsefl) and the underlying asset which is also expected to be an ERC-20 token.

This is essentially the same we have in Super Tokens, just with different terminology.

ERC-4626 -> Super Token

asset() -> getUnderlyingToken() totalAssets() -> totalSupply() (since Super Token has a 1:1 peg) convertToShares() -> not yet implemented, may become fromUnderlyingAmount(), see https://github.com/superfluid-finance/protocol-monorepo/issues/1317 convertToAssets() -> toUnderlyingAmount() mint() -> upgrade() deposit() -> not yet implemented - basically the same as mint(), but with the amount argument denominated in assets / underlying redeem() -> downgrade() withdraw() -> not yet implemented - basically the same as redeem(), but with the amount argument denominated in assets / underlying

The interface has a few more functions, e.g. previewX() view functions for simulating actions and maxMint() for allowing to cap how much can be deposited, also events.

The most significant difference between Super Token Wrappers as is and an ERC-4626 enabled Super Token would be that there's no 1:1 peg between underlying and Super Token anymore. I believe a Super Token Wrapper without 1:1 peg wouldn't violate any assumptions. The conversion between Super Token amounts and underlying amounts currently only takes into account the possibility of having to shift decimals. A ERC-4626 implementation would bring its own logic for doing this conversion - usually just a proportional mapping.

Possible next step

Implement a Custom Super Token which implements a simple ERC-4626. Requires custom Super Token logic (not just custom proxy).
If there's demand for it, we could consider providing builtin support for ERC-4626, e.g. add methods to the SuperTokenFactory for creating instances.

Streaming Mint

One of the projects looking into ERC-4626 Super Tokens is said to want to do streaming mint. My understanding is that the shares argument of function mint(uint256 shares, address receiver) - which is usually the amount of shares minted to the receiver - shall be interpreted as a flowrate in that scenario.

Option 1: use CFA

We do have a (currently unmaintained) experimental Custom Super Token implementation doing streaming mint: StreamFromMint.sol. Here, type(int256).max tokens are minted to the token contract itself, so it can create an effectively never ending (in practice it may become insolvent in a gazillion years or so) CFA "minting stream". This implementation works using the stock SuperToken logic. Caveat: the sum of all balances is not equal to totalSupply(). Which may in theory not matter, but isn't pretty.

Pro: quite easy, can be done using canonical SuperToken logic Contra: a bit dirty / hacky

Option 2: customize balanceOf()

An alternative implementation could override balanceOf() and do something like this:

function balanceOf(address account) external returns(uint256 balance) {
        if (account == _mintingReceiver) {
            return toU256(_mintingRate) * (block.timestamp - _mintingStartTime);
        } else {
            _fallback();
        }
    }

This currently requires customization of the SuperToken logic as the proxy's balanceOf() won't be used by internal calls.

Pro: would satisfy the invariant sum(balanceOf()) = totalSupply() Contra: currently not doable without customized SuperToken logic, thus increased maintenance cost for the resulting token

Option 3 (?): use SemanticMoney library

This is speculation, I didn't spend time verifying my gut feeling.

Interpreting ERC-4626 shares as a flowrate means the resulting gauge is an integration of this shares over time. That's the same we're doing with GDA Pool units in flow distributions. Thus it may be possible (and a good idea?) to leverage the semantic-money library for implementing this use case.

Pro: seems elegant Contra: not sure if viable, engineering effort