Skip to main content

YB Token

The source code of the YB.vy contract can be found on GitHub. The contract is written with Vyper version 0.4.3.

Overview

The YB contract is the governance token for the Yield Basis protocol. It extends standard ERC20 functionality with inflationary emissions that follow an exponential decay curve. The token implements a minting mechanism where authorized minters (GaugeController) can emit tokens based on time elapsed and a configurable rate factor.

  • Exponential Decay Emissions: Token emissions follow an exponential decay curve
  • Reserve-Based Minting: Total supply is limited by a reserve amount
  • Rate Factor Control: Minters can control emission rate via rate_factor parameter
  • Ownable + Minter System: Combines ownership control with minter permissions
  • Controlled Emissions Start: Emissions clock starts when ownership is renounced or start_emissions() is called
  • Minter-Based Minting: Actual tokens are minted only when authorized minters call emit()

Related: See GaugeController for emission distribution and VotingEscrow for governance voting.

Public Variables

Emission State

  • reserve (uint256) - Remaining tokens available to be minted
  • last_minted (uint256) - Timestamp of the last minting event
  • max_mint_rate (uint256) - Maximum emission rate (immutable)

Function Documentation

_emissions()

Description:
Internal function that calculates the amount of tokens to emit based on time elapsed and rate factor. Uses exponential decay formula.

Returns:
uint256 - Amount of tokens to emit.

InputTypeDescription
tuint256Target timestamp for emission calculation
rate_factoruint256Rate factor (100% = 10^18)
📄 View Source Code
@internal
@view
def _emissions(t: uint256, rate_factor: uint256) -> uint256:
assert rate_factor <= 10**18
last_minted: uint256 = self.last_minted
if last_minted == 0 or t <= last_minted:
return 0
else:
dt: int256 = convert(t - last_minted, int256)
rate_36: int256 = convert(max_mint_rate * rate_factor, int256)
reserve: int256 = convert(self.reserve, int256)
return convert(
reserve * (10**18 - math._wad_exp(-dt * rate_36 // 10**18)) // 10**18,
uint256)

Formula:
amount = reserve * (1 - exp(-dt * max_mint_rate * rate_factor / 10^18))

Where rate_factor ∈ [0, 10^18] and dt is the time elapsed since last mint.


</div>
</details>

</div>

---

<div class="doc-box">

### `preview_emissions()`

<div class="divider"></div>

**Description:**
View function to preview the amount of tokens that would be emitted for a given timestamp and rate factor.

> **Note:** This is the token-level `preview_emissions()`. The `GaugeController` also has a `preview_emissions(gauge, at_time)` function for per-gauge emission previews.

**Returns:**
`uint256` - Preview of tokens to be emitted.

| Input | Type | Description |
|-------|------|-------------|
| `t` | `uint256` | Target timestamp for emission calculation |
| `rate_factor` | `uint256` | Rate factor (100% = 10^18) |

<details>
<summary>📄 View Source Code</summary>

<div>

```python
@external
@view
def preview_emissions(t: uint256, rate_factor: uint256) -> uint256:
return self._emissions(t, rate_factor)

start_emissions()

Description:
Starts the emission process by setting the initial timestamp. Only callable by the owner.

Emits:
None.

📄 View Source Code
@external
def start_emissions():
ownable._check_owner()
if self.last_minted == 0:
self.last_minted = block.timestamp

renounce_ownership()

Description:
Renounces ownership and forces emissions to start if not already started. Removes the caller as a minter.

Emits:
RoleMinterChanged - When the caller is removed as a minter.

📄 View Source Code
@external
def renounce_ownership():
ownable._check_owner()
# Force-start emissions when renouncing ownership
if self.last_minted == 0:
self.last_minted = block.timestamp
erc20.is_minter[msg.sender] = False
log erc20.RoleMinterChanged(minter=msg.sender, status=False)
ownable._transfer_ownership(empty(address))

emit()

Description:
Mints tokens to the specified owner based on time elapsed and rate factor. Only callable by authorized minters.

Returns:
uint256 - Amount of tokens minted.

Emits:
Transfer - When tokens are minted from address(0) to the owner.

InputTypeDescription
owneraddressAddress to receive the minted tokens
rate_factoruint256Rate factor (100% = 10^18)
📄 View Source Code
@external
def emit(owner: address, rate_factor: uint256) -> uint256:
assert erc20.is_minter[msg.sender], "erc20: access is denied"

amount: uint256 = 0

if self.last_minted > 0:
amount = self._emissions(block.timestamp, rate_factor)
self.reserve -= amount
self.last_minted = block.timestamp
erc20._mint(owner, amount)

return amount

Emission Mechanics

The YB token implements a sophisticated emission system with exponential decay and rate factor control:

Exponential Decay Formula

The emission calculation uses an exponential decay formula:

emission = reserve * (1 - e^(-dt * rate * rate_factor))

Where:

  • dt = time elapsed since last mint
  • rate = max_mint_rate (immutable)
  • rate_factor = percentage of max rate (0-100%)
  • reserve = remaining tokens available

Rate Factor Control

  • 100% rate = rate_factor = 10^18
  • 50% rate = rate_factor = 5 * 10^17
  • 0% rate = rate_factor = 0

Integration with GaugeController

The YB token is designed to work with the GaugeController that:

  • Controls emission rates via rate_factor parameter
  • Distributes rewards to different gauges/pools
  • Manages governance through token voting power

In Yield Basis deployments, GaugeController is granted the minter role and mints to itself, then distributes to gauges. The token contract is generic and simply enforces erc20.is_minter[address] permissions.

See also: VotingEscrow for how locked YB tokens provide voting power in the governance system.

Emission Timeline

  1. Deployment: reserve and max_mint_rate are set (max_mint_rate is immutable)
  2. Emissions Start: Clock starts when ownership is renounced or start_emissions() is called
  3. Minting: Authorized minters call emit() to mint tokens
  4. Decay: Emission rate decreases exponentially over time
  5. Completion: When reserve reaches 0, no more tokens can be minted