---
# System prepended metadata

title: 'Spendable Yield Tokens (SYTs): Yield you can actually spend'
tags: [protocol-design, ethereum, defi, automation, erc20, token-design, yield, defi-ux, smart-contracts, solidity]

---

# Spendable Yield Tokens (SYTs): Yield you can actually spend

Yield tokens are one of DeFi’s best primitives. They are also one of its worst UX traps.

A yield token is a tokenized claim on assets earning interest in a protocol like Aave. When you hold it, your balance grows over time as yield accrues. That works well for earning, but it is awkward for paying. If you send Aave’s aUSDC to a friend, they receive aUSDC, even though they likely want plain USDC.

Spendable Yield Tokens fix this. An SYT represents a yield bearing position, but when it is transferred, the value automatically settles as the underlying asset for the recipient. Yield continues to accrue for the holder, while spending works the way money is expected to work.

![image](https://hackmd.io/_uploads/BkvC8x8rWe.png)


For yield to feel like savings, it needs to stay out of the way and behave like money by default.

---

## TL;DR

* **SYTs** are yield tokens built around a **spend first UX**.
* They behave like yield bearing claims under the hood but are engineered so value settles as the **underlying asset** when you transfer or spend.
* The first SYT we are building is **sUSDC**, or spendable USDC.

---

## The UX problem: yield tokens do not spend like money

Aave’s aUSDC is a solid yield bearing asset, but it is not designed to be spent directly.

![image](https://hackmd.io/_uploads/ryrhT1UBZl.png)

When you hold aUSDC, your USDC is deposited in Aave and represented by a yield token. That yield token can be transferred, but most recipients do not want a yield position. They want USDC they can use immediately.

To send USDC to someone, you cannot simply transfer [aUSDC][1]. You first have to unwind the position. That means redeeming aUSDC back into USDC through Aave, waiting for the withdrawal to settle, and only then sending USDC to the recipient. Each step adds friction, costs gas, and forces the sender to think about yield mechanics at the exact moment they want to pay.

---

## What is an SYT?

An SYT is a token that represents a user’s share of assets deployed into yield strategies, with a transfer mechanism that routes settlement in a spend friendly way.

In practice, for **sUSDC**:

* Users accrue yield via exposure to Aave.
* Users can hold yield in a token that stays liquid.
* When **sUSDC is spent**, settlement can occur as **USDC** to the recipient, while the sender’s yield position is adjusted internally.

That last point is key. **Spend is a first class operation, not an afterthought.**

---

## How we implement SYTs (high level)

Our [SYT implementation](https://github.com/locker-labs/autohodl.money/pull/36) centers on two core components:

* **`LockerSYT`**, the SYT token, which tracks share ownership and exposes a standard ERC20 interface.
* **`LockerRouter`**, the system router, which is authoritative for NAV, or net asset value, across yield adapters and decides how transfers settle.

A crucial design choice is that **user visible balances are derived from NAV**, not from simple stored integers.

---

## Shares vs assets: why `balanceOf` is rebasing style
![image](https://hackmd.io/_uploads/ByIgzx8rZx.png)

`LockerSYT` stores balances in share units called `balanceOfSYT` and derives user facing balances as a proportional claim on the underlying assets managed by the router:

```solidity
function totalAssets() public view returns (uint256) {
    ILockerRouter.Allocation memory alloc = router.getDefaultAllocation(parentToken);
    return router.navAcrossAdapters(alloc.adapters, parentToken);
}

function balanceOf(address account) public view returns (uint256) {
    uint256 ts = totalSupply;
    if (ts == 0) return 0;

    return Math.mulDiv(
        balanceOfSYT[account],
        totalAssets(),
        ts,
        Math.Rounding.Floor
    );
}
```

This model gives us:

* **Composable yield accounting**. If NAV grows, `balanceOf()` grows without rewriting every user balance.
* **Strategy flexibility**. NAV can come from one adapter today and multiple adapters later.
* **A clean mental model**. The SYT represents a claim on assets, not a fixed pile of tokens.

This means balances grow as yield accrues without requiring explicit rebases or per user updates.

---

## The spendable part: transfers are routed

In a normal ERC20, transfers are bookkeeping. You subtract from the sender and add to the receiver.

SYTs are different. Transfers are a chance to settle value.

In `LockerSYT`, both `transfer` and `transferFrom` route through `_routedTransfer`, which consults the router:

```solidity
function transfer(address to, uint256 value) external nonReentrant returns (bool) {
    return _routedTransfer(msg.sender, to, value);
}

function transferFrom(address from, address to, uint256 value) external nonReentrant returns (bool) {
    uint256 allowed = allowance[from][msg.sender];
    if (allowed != type(uint256).max) {
        if (allowed < value) revert InsufficientAllowance();
        unchecked { allowance[from][msg.sender] = allowed - value; }
    }
    return _routedTransfer(from, to, value);
}

function _routedTransfer(address from, address to, uint256 amount) internal returns (bool) {
    if (amount == 0) {
        return false;
    }

    if (from == address(0) || to == address(0)) revert InvalidTransfer();

    (uint256 sharesToSend, address routeTo) =
        router.sendUnderlying(parentToken, from, to, amount);

    if (routeTo == address(0)) {
        _burn(from, sharesToSend);
    } else {
        _poolTransfer(from, routeTo, sharesToSend);
        emit Routed(from, to, sharesToSend, routeTo);
    }

    emit Transfer(from, to, amount);
    return true;
}
```

Important details:

* `router.sendUnderlying(...)` is where **spendable settlement logic lives**.
* The SYT contract determines how many shares the transfer represents and delegates settlement decisions to the router.
* The contract emits two signals:
  * `Routed(...)` which records how the transfer actually settled.
  * `Transfer(from, to, amount)` which preserves ERC20 compatibility and user intent.

The ERC20 `Transfer` event captures the user’s intent, such as paying someone a specific amount. The `Routed` event captures how the system fulfilled that intent.

---

## Minting, burning, and trust boundaries

`LockerSYT` is not freely mintable. Supply changes are restricted to trusted system components via the router:

```solidity
modifier routerOnly() {
    if (msg.sender != address(router)) revert TransferBlocked();
    _;
}

function mint(address to, uint256 amount) external routerOnly {
    _mint(to, amount);
}

function burn(address from, uint256 amount) external routerOnly {
    _burn(from, amount);
}
```

This ensures:

* **Supply integrity**. Only the router can adjust supply during deposits, withdrawals, and settlements.
* **Cleaner audits**. There are fewer supply mutation points and simpler invariants to reason about.

Transfer paths are also guarded with `nonReentrant`, since settlement can involve external adapter calls.

---

## autoHODL and SYTs

[autoHODL](autohodl.money) is a new project by Locker focused on passive crypto savings. The goal is to make saving happen automatically, without requiring users to actively manage positions or think about yield mechanics.

At a high level, autoHODL works by rounding up everyday onchain spending, depositing the difference into yield strategies like Aave, and letting it compound quietly in the background. It works with any wallet and is designed to integrate naturally into existing spending flows.

SYTs are how that yield becomes usable.
![Screenshot 2026-01-14 at 22.54.33](https://hackmd.io/_uploads/HyrMQeIHbx.png)

---

## Tradeoffs and design notes

SYTs intentionally blur the boundary between token transfer and value settlement. That unlocks better UX but introduces real engineering considerations:

* **Rounding**. `mulDiv(..., Rounding.Floor)` is conservative, and small rounding effects exist.
* **Indexing semantics**. Indexers may need to consume `Routed` events to understand settlement destinations.
* **Gas costs**. Routed transfers cost more than plain ERC20 bookkeeping. This is a deliberate UX tradeoff.
* **Router complexity**. The router is the primary correctness surface for NAV, adapter accounting, and settlement rules.

These tradeoffs are acceptable for our target experience, but worth stating explicitly.

---

## Roadmap

We are starting with sUSDC because it aligns with USDC based spending and yield strategies on Linea. From there:

* Support more parent tokens as integrations expand.
* Add more yield strategies and adapters beyond Aave.
* Introduce additional spendable yield assets where it makes sense.
* Address gas costs with proxy pools.

---

## Closing

If DeFi is going to onboard more people, yield cannot feel like a separate mode you enter and exit. It needs to behave like savings. Quietly compounding in the background and always available when you need it.

That is what SYTs are for.

If you are a builder interested in this design space, reach out. We would love feedback as we ship the first production SYTs. For updates, follow us on X at [@autoHODL](@autoHODL).

![Gemini_Generated_Image_5bux4l5bux4l5bux](https://hackmd.io/_uploads/SyZjLeLr-x.jpg)


---

[1]: https://hackmd.io/%40ChloeIsCoding/SyOP3QVXZg?utm_medium=rec&utm_source=chatgpt.com "Understanding Aave V2 Code (4/n) Withdraw Mechanism"