ERC-7770: Fractional Reserve Token

Abstract

We propose a new token standard for synthetic assets that are only partially redeemable to their underlying asset, but fully backed by other collateral assets.

The standard defines an interface to mint fractional reserve assets, and a standard to reflect economical risk related data to the token holders and lenders.

Motivation

The Cambrian explosion of new L1s and L2s gave rise to bridged assets which are synthetic by nature. Indeed, ETH on Arbitrum L2, or WETH on Binance Smart Chain are not fully fungible with their mainnet counterpart. However, these assets are fully backed by their mainnet counterpart and guaranteed to be redeemable to their mainnet underlying asset, albeit with certain time delay.

Fractional reserve tokens can allow an ecosystem (chains, L2s, and other networks of economic activity) to increase its supply by allowing users to mint the asset not only by bridging it to the ecosystem, but also by borrowing it (typically against a collateral).

As an example, consider a fractional reserve token, namely, frDAI, that represents a synthetic DAI.
Such token will allow users to mint 1 frDAI upon deposit of 1 DAI, or by providing a collateral that worth more than 1 DAI.
Quick redemption of frDAI to DAI is available as long as there is still some DAI balance in the frDAI token, and otherwise, the price of frDAI may temporarily fluctuate until borrowers repay their debt.

Fractional reserve tokens may delegate minting capabilities for multiple risk curators and lending markets. Hence, a uniform standard for fractional reserve minting is needed.
Fractional reserve banking does not come without risks, such as insolvency or a bank run.
This standard does not aim to dictate economic risk management practices, but rather to have a standard on how to reflect the risk to token holders.

Specification

The proposed standard has the following requirements:

Interface

interface IERCXXX is IERC20 {
    // events
    event MintFractionalReserve(address indexed minter, address to, uint256 amount);
    event BurnFractionalReserve(address indexed burner, address from, uint256 amount);
    event SetSegregatedAccount(address account, bool segregated);

    // functions
    // setters
    function fractionalReserveMint(address _to, uint256 _amount) external;
    function fractionalReserveBurn(address _from, uint256 _amount) external;
 
   // getters
    function totalBorrowedSupply() external view returns (uint256);
    function requiredReserveRatio() external view returns (uint256);
    function segregatedAccount(address _account) external view returns (bool);
    function totalSegregatedSupply() external view returns (uint256);
}

Reserve ratio

The reserve ratio reflects the ratio between the token that is available as cash, i.e., available for an immediate redemption (or alternatively, a token that was not minted via a fractional reserve minting), and the total supply of the token. Segregated accounts MUST be subtracted from the cash balance.
Lower reserve ratio gives rise to higher capital efficiency, however it increases the likelihood of depeg or a run on the bank, where token holders cannot immediately redeem their synthetic token.

Formally, the reserve ratio is denoted by $$\frac{totalSupply() - totalBorrowedSupply() - \sum_{a \in \text{Segregated Accounts}} \text{balanceOf}(a)}{totalSupply()}$$.
Additional fractional reserve minting MUST NOT occur when the reserve ratio, multiplied by 1e18 is lower than requiredReserveRatio().

Mint and burn functionality

The fractionalReserveMint and fractionalReserveBurn functions SHOULD be called by permissioned addresses, e.g., risk curators or lending markets. These entities SHOULD mint new tokens only to addresses that already locked collateral in a dedicated contract.

The reserve ratio is denoted by $$\frac{totalSupply() - \sum_{a \in \text{Segregated Accounts}} \text{balanceOf}(a)}{totalSupply() + totalBorrowedSupply()}$$.
fractionalReserveMint MUST revert if the reserve ratio, multiplied by e18 exceeds requiredReserveRatio().

A successful call to fractionalReserveMint(_to, _amount) MUST increase the value of totalSupply(), totalBorrowedSupply(), and the token balance of address _to, by _amount units.
A call to fractionalReserveMint MUST emit a MintFractionalReserve event.
A call to fractionalReserveMint MUST revert if after the mint the reserve ratio, multiplied by 1e18 exceeds the value of requiredReserveRatio().

Similarly, a successful call to fractionalReserveBurn(_from, _amount) MUST decrease the value of totalSupply(),totalBorrowedSupply(), and the token balance of address _from by _amount units.
A call to fractionalReserveBurn MUST emit a BurnFractionalReserve event.

Segregated accounts

Increasing the total supply could be a concern if a token is used for DAO votes and/or if dividends are distributed to token holders.
In order to mitigate such concerns, segregated accounts are introduced, with the premise that money in these accounts is not counted towards the reserve, and therefore, additional token supply cannot be minted against them.

At every point in time, it MUST hold that the sum of token balances for segregated addresses equals to totalSegregatedSupply().

Account balance

The fractionalReserveMint SHOULD be used in conjunction with a lending operation, where the minted token is borrowed. The lending operation SHOULD come with an interest rate, and some of the interest rate proceedings SHOULD be distributed to token holders that are not in segregated accounts.
This standard does not dictate how distribution should occur.

Rationale

The proposed standard aims to standardise how multiple lending markets and risk providers can interact with a fractional reserve token. The actual lending operation should be done carefully by trusted entities, and it is the token owner’s responsibility to make sure the parties who have fractional reserve minting credentials are reliable.

At the core of the coordination relies the need to understand how much additional supply is available for borrow, and at what interest rate. The additional borrowable supply is deduced from the required reserve ratio, and the total, borrowable and segregated supply.
The interest rate SHOULD be monotonically increasing with the current reserve ratio.

The standard does not dictate how the accrued interest rate is distributed. One possible distribution is by making the token a rebased token. An alternative way is to introduce staking, or just airdropping of proceeds.

While a fractional reserve is most useful when it is backed by a known asset, e.g., frDAI and DAI, it can also be used in isolation. In such a case, a token will have a fixed initial supply, however additional supply can be borrowed. In such cases the supply temporarily increases, but the net holdings (totalSupply() - totalBorrowedSupply()) remains unchanged.

Backwards Compatibility

Fractional reserve tokens should be backwards compatible with ERC-20.

Reference Implementation

// The code below is provided only for illustration, DO NOT use it in production
contract FractionalReserveToken is ERC20, Ownable {

    event MintFractionalReserve(address indexed minter, address to, uint256 amount);
    event BurnFractionalReserve(address indexed burner, address from, uint256 amount);
    event SetSegregatedAccount(address account, bool segregated);

    /// @notice token supply in these accounts is not counted towards the reserve, and
    /// therefore, additional token supply cannot be minted against them.
    mapping(address => bool) public segregatedAccount;

    /// @notice ratio between the token that is available as cash (immediate redemption)
    /// and the total supply of the token.
    uint256 public requiredReserveRatio;

    uint256 public totalBorrowedSupply;

    constructor(
        string memory _name,
        string memory _symbol
    ) ERC20(_name, _symbol) Ownable(msg.sender) {}

    function fractionalReserveMint(address to, uint256 amount) external onlyOwner {
        _mint(to, amount);
        totalBorrowedSupply += amount;
        emit MintFractionalReserve(msg.sender, to, amount);

        uint256 reserveRatio = (totalSupply() - totalBorrowedSupply - segregatedSupply) * 1e18 / totalSupply();
        require(reserveRatio >= requiredReserveRatio, "reserveRatio");
    }
    function fractionalReserveBurn(address from, uint256 amount) external onlyOwner {
        _burn(from, amount);
        totalBorrowedSupply -= amount;
        emit BurnFractionalReserve(msg.sender, from, amount);
    }

    // ------------------------------------------------------------------------------
    // Code below is not part of the proposed standard
    // ------------------------------------------------------------------------------
    uint256 internal segregatedSupply; // supply of segregated tokens

    function _update(address from, address to, uint256 value) internal override {
        // keep the reserve up to date on transfers
        if (!segregatedAccount[from] && segregatedAccount[to]) {
            segregatedSupply += value;
        }
        if (segregatedAccount[from] && !segregatedAccount[to]) {
            segregatedSupply -= value;
        }
        ERC20._update(from, to, value);
    }

    function mint(address account, uint256 value) external onlyOwner {
        _mint(account, value);
    }

    function burn(address account, uint256 value) external onlyOwner {
        _burn(account, value);
    }

    function setSegregatedAccount(address account, bool segregated) external onlyOwner {
        if (segregated) {
            require(!segregatedAccount[account], "segregated");
            segregatedSupply += balanceOf(account);
        } else {
            require(segregatedAccount[account], "!segregated");
            segregatedSupply -= balanceOf(account);
        }
        segregatedAccount[account] = segregated;
        emit SetSegregatedAccount(account, segregated);
    }

    function setRequiredReserveRatio(uint256 value) external onlyOwner {
        requiredReserveRatio = value;
    }
}

Security Considerations

Fractional reserve banking comes with many economic risks. This standard does not aim to provide guidelines on how to properly mitigate them.

Copyright

Copyright and related rights waived via CC0.

I’m worried that the risk profile of an asset to which this standard would be applicable would be inherently tightly coupled to the details of whatever contracts are permitted to call the mint/burn functions, and more particularly to the details of how such a collateral locking scheme might be implemented, which suggests that a standard intended to communicate the risk profile must also include standards for these other aspects.

How, for example, is fractionalReserveMint() supposed to check that the reserve ratio is below requiredReserveRatio() before minting? The minter knows the supply of the token but doesn’t necessarily have any economic information about the value of the collateral the minters SHOULD (not MUST!) be keeping track of.

Reserve ratio isn’t enough information to communicate a risk profile, either. What if the collateral is illiquid? I’ve seen protocols that maintain a theoretically 100% reserve ratio by diluting collateral liquidity on redemptions. (This sounds very sophisticated, but it functionally equivalent to saying they’ll definitely pay you back eventually, when the scammers who constructed the scheme get around to repaying the funds they raided from the protocol’s vault.)

1 Like

Yes, you are right that it is far from reflecting the full picture regarding the risk, and rather just help coordinate between different agents who operate lending markets on top of the fractional reserve token.

Reflecting the full risk picture is beyond the scope of this ERC, and very hard task in general.