SRC-5115: Wrapped yield-bearing token

SRC-5115: Standardized Yield Token Standard

Abstract

This specification defines a standardized interface for yield-bearing tokens on the Fuel blockchain. Building upon the SRC-20 standard, it introduces functionality for depositing assets, redeeming shares, and tracking exchange rates for yield-generating mechanisms. The standard enables seamless integration between different yield protocols and provides a consistent interface for yield-bearing token operations.

Key Concepts

SCY Token (Standardized Composable Yield Token): A standardized yield-bearing token that represents ownership in a yield-generating pool. SCY tokens are minted when users deposit assets and can be redeemed for underlying assets plus accumulated yield. SRC-5115 contract mints only one asset (the SCY token itself) regardless of the variety of input tokens supported.

Shares: Units of ownership in the yield-generating pool. Each share represents a proportional claim on the underlying assets and accumulated yield. The number of shares a user receives is determined by the exchange rate at the time of deposit.

Exchange Rate: The ratio between the total value of underlying assets in the pool and the total number of shares. As the pool generates yield, the exchange rate increases, making each share worth more underlying assets over time.

Motivation

This standard is heavily inspired by Ethereum’s ERC-5115.

DeFi protocols implement yield generation through diverse mechanisms, requiring custom integration for each new protocol combination. This fragmentation creates barriers to interoperability and increases development overhead. The SRC-5115 standard addresses this by providing a unified interface for yield-bearing tokens across various DeFi mechanisms.

The standard accommodates multiple yield-generating scenarios:

  • Yield-bearing assets that have different input tokens used for minting vs accounting for the pool value
  • Assets with reward tokens by default (e.g., lending rewards)
  • Liquid staking positions
  • AMM liquidity provision tokens
  • Rebasing tokens

Specification

Core Interface

The SRC-5115 standard defines the following ABI interface:

abi SRC5115 : SRC20 {
    #[payable, storage(read, write)]
    fn deposit(
        receiver: Identity,
        token_in: AssetId,
        amount_token_to_deposit: u64,
        min_shares_out: u64,
    ) -> u64;

    #[payable, storage(read, write)]
    fn redeem(
        receiver: Identity,
        token_out: AssetId,
        amount_shares_to_redeem: u64,
        min_token_out: u64,
    ) -> u64;

    #[storage(read)]
    fn exchange_rate() -> u256;

    #[storage(read)]
    fn get_tokens_in() -> Vec<AssetId>;

    #[storage(read)]
    fn get_tokens_out() -> Vec<AssetId>;

    #[storage(read)]
    fn yield_token() -> AssetId;

    #[storage(read)]
    fn preview_deposit(token_in: AssetId, amount_token_to_deposit: u64) -> u64;

    #[storage(read)]
    fn preview_redeem(token_out: AssetId, amount_shares_to_redeem: u64) -> u64;
}

struct DepositEvent {
    caller: Identity,
    receiver: Identity,
    token_in: AssetId,
    amount_deposited: u64,
    amount_sy_out: u64,
}

struct RedeemEvent {
    caller: Identity,
    receiver: Identity,
    token_out: AssetId,
    amount_sy_to_redeem: u64,
    amount_token_out: u64,
}

Required Functions

deposit

#[payable, storage(read, write)]
fn deposit(
    receiver: Identity,
    token_in: AssetId,
    amount_token_to_deposit: u64,
    min_shares_out: u64,
) -> u64;

Deposits amount_token_to_deposit of input token token_in and mints shares to receiver.
Parameters:

  • receiver: The Identity that will receive the minted shares
  • token_in: The AssetId of the token being deposited
  • amount_token_to_deposit: The amount of tokens to deposit
  • min_shares_out: The minimum amount of shares to receive (slippage protection)

Returns:

  • u64: The actual amount of shares minted

Requirements:

  • MUST emit a Deposit event
  • MUST revert if amount of minted shares is less than min_shares_out.

redeem

#[payable, storage(read, write)]
fn redeem(
    receiver: Identity,
    token_out: AssetId,
    amount_shares_to_redeem: u64,
    min_token_out: u64,
) -> u64;

Redeems amount_shares_to_redeem shares for token_out tokens and transfers them to receiver.

Parameters:

  • receiver: The Identity that will receive the redeemed tokens
  • token_out: The AssetId of the token to receive
  • amount_shares_to_redeem: The amount of shares to redeem
  • min_token_out: The minimum amount of tokens to receive (slippage protection)

Returns:

  • u64: The actual amount of tokens redeemed

Requirements:

  • MUST emit a Redeem event
  • MUST revert if redeemed amount of tokens is less than min_token_out

exchange_rate

#[storage(read)]
fn exchange_rate() -> u256;

Returns the current exchange rate between shares and underlying assets, scaled by a fixed scaling factor (1e18).

Returns:

  • u256: The current exchange rate scaled by 1e18

Requirements:

  • MUST return the current exchange rate such that exchange_rate * shares / 1e18 = assets
  • MUST NOT include fees that are charged against the underlying yield token

Calculation:
The exchange rate is calculated as:

exchange_rate = (total_underlying_assets * EXCHANGE_RATE_SCALE) / total_shares

Where:

  • total_underlying_assets is the total value of underlying assets in the pool
  • total_shares is the total supply of SCY tokens (shares)
  • EXCHANGE_RATE_SCALE is typically 1e18 for precision

As the pool generates yield, the total underlying assets increase while the total shares remain constant, causing the exchange rate to increase over time.

get_tokens_in

#[storage(read)]
fn get_tokens_in() -> Vec<AssetId>;

Returns the list of all input tokens that can be used to deposit.

Returns:

  • Vec<AssetId>: Array of AssetIds that can be deposited

Requirements:

  • MUST return at least one AssetId

get_tokens_out

#[storage(read)]
fn get_tokens_out() -> Vec<AssetId>;

Returns the list of all output tokens that can be converted into when redeeming.

Returns:

  • Vec<AssetId>: Array of AssetIds that can be redeemed

Requirements:

  • MUST return at least one AssetId

yield_token

#[storage(read)]
fn yield_token() -> AssetId;

Returns the underlying yield-bearing token AssetId.

Returns:

  • AssetId: The underlying yield-bearing token AssetId

preview_deposit

#[storage(read)]
fn preview_deposit(token_in: AssetId, amount_token_to_deposit: u64) -> u64;

Returns the amount of shares that would be minted if amount_token_to_deposit of token_in were deposited.

Parameters:

  • token_in: The AssetId of the token to be deposited
  • amount_token_to_deposit: The amount of tokens to deposit

Returns:

  • u64: The amount of shares that would be minted

Requirements:

  • MUST return less than or equal to the actual return value of the deposit method
  • SHOULD NOT return greater than the actual return value of the deposit method

preview_redeem

#[storage(read)]
fn preview_redeem(token_out: AssetId, amount_shares_to_redeem: u64) -> u64;

Returns the amount of token_out that would be received if amount_shares_to_redeem shares were redeemed.

Parameters:

  • token_out: The AssetId of the token to receive
  • amount_shares_to_redeem: The amount of shares to redeem

Returns:

  • u64: The amount of tokens that would be received

Requirements:

  • MUST return less than or equal to the actual return value of the redeem method
  • SHOULD NOT return greater than the actual return value of the redeem method

Events

The SRC-5115 standard defines the following events:

DepositEvent

pub struct DepositEvent {
    caller: Identity,
    receiver: Identity,
    token_in: AssetId,
    amount_deposited: u64,
    amount_sy_out: u64,
}

Emitted when input tokens are deposited into the SRC-5115 contract via the deposit method.

Fields:

  • caller: The Identity that initiated the deposit
  • receiver: The Identity that received the shares
  • token_in: The AssetId of the deposited token
  • amount_deposited: The amount of tokens deposited
  • amount_sy_out: The amount of shares minted

RedeemEvent

pub struct RedeemEvent {
    caller: Identity,
    receiver: Identity,
    token_out: AssetId,
    amount_sy_to_redeem: u64,
    amount_token_out: u64,
}

Emitted when shares are redeemed from the SRC-5115 contract via the redeem method.

Fields:

  • caller: The Identity that initiated the redemption
  • receiver: The Identity that received the tokens
  • token_out: The AssetId of the redeemed token
  • amount_sy_to_redeem: The amount of shares redeemed
  • amount_token_out: The amount of tokens received

Multiple Input/Output Tokens Support

SRC-5115 contracts may support multiple input and output tokens, providing flexibility for different yield-generating mechanisms. This allows users to deposit various assets and redeem into different tokens based on their needs.

Examples of Multi-Token Support

The following examples are taken from Ethereum’s Pendle protocol:

1. Liquid Staking Derivatives (Pendle wstETH SCY)

  • Input tokens: ETH, wstETH
  • Output tokens: ETH, wstETH
  • Use case: Users can deposit ETH (which gets wrapped to wstETH) or directly deposit wstETH, and redeem into either ETH or wstETH

2. Money Market Supply (Pendle Compound SCY)

  • Input tokens: USDC, cUSDC
  • Output tokens: USDC, cUSDC, COMP (reward token)
  • Use case: Users can deposit USDC (which gets supplied to Compound) or directly deposit cUSDC, and redeem into USDC, cUSDC, or claim COMP rewards

Implementation Guidelines

Exchange Rate Calculation

The exchange rate should be calculated as:

exchange_rate = (total_underlying_assets * exchange_rate_scale) / total_shares

Where:

  • total_underlying_assets is the total value of underlying assets in the pool
  • total_shares is the total supply of SRC-5115 shares
  • exchange_rate_scale is typically 1e18 for precision

Share Calculation

When depositing tokens:

shares_to_mint = (amount_deposited * exchange_rate_scale) / exchange_rate

When redeeming shares:

tokens_to_receive = (shares_to_redeem * exchange_rate) / exchange_rate_scale

Security Considerations

  • Malicious implementations that conform to the interface can put users at risk
  • All integrators should review implementations to avoid possible exploits
  • The yield_token function must accurately reflect the underlying yield-bearing token
  • Exchange rate calculations should be protected against manipulation
  • Proper access controls should be implemented for administrative functions

Compatibility

All SRC-5115 tokens are also SRC-20 compliant and can be used in any SRC-20 context.

Related Standards

References

1 Like

Thanks for proposing! Our team is looking into it and will share their thoughts soon

1 Like