# Introducing Affine Restaking

**Affine ultraLRTs** are the most robust Symbiotic and Eigenlayer Liquid Restaking Tokens (LRTs) offering the **fastest entry-exit, non-dilutive AVS yield**, and are powered by [Affine Risk Engine ](/affine-restaking/affine-risk-engine)to mitigate risk and maximize returns. Affine’s [ultraETH and ultraETHs](/affine-restaking/ultraeth-and-ultraeths) are engineered to provide restaking utility to $25 billion+ of stETH market, while leveraging the deep liquidity of Lido stETH.

#### Unique Features

1. **Robust and Most Liquid:** Affine is the most robust LRT with sophisticated risk research and superior liquidity, benefiting from stETH's deep liquidity. For other LRTs, it may take weeks to get liquidity without slippage, due to Ethereum beacon chain's entry and exit time delay. However, using stETH, Affine is able to provide a much faster, low slippage liquidity alterntive.
2. **Affine Affine Risk Engine:** We launched the risk engine to collaborate with the restaking industry, creating a framework for safely selecting operators and AVSs. Developed by industry leaders and researchers from Goldman Sachs, Meta, Y Combinator, MIT, and Harvard, it aims to simplify the launch of decentralized ecosystems.&#x20;
3. [**Highest, Undiluted AVS Airdrops**](/affine-restaking/undiluted-avs-rewards)**:** Affine plans to grow with the ecosystem’s crypto economic security demand capacity, instead of diluting AVS points for all the restakers. Coupled with our relationships with AVSs and Operators, this allows us to provide undiluted APY on any future AVS airdrops.

Restake on both Eigenlayer and Symbiotic NOW!

{% embed url="<https://restaking.affinedefi.com/>" %}
[https://restaking.affinedefi.com](https://restaking.affinedefi.com/)
{% endembed %}


# Affine Risk Engine

The Affine Risk Engine is a cutting-edge research hub enabled by ultraETH, aimed at enhancing the security and reliability of early-stage Actively Validated Services (AVSs) on the EigenLayer. By leveraging ultraETH, the Affine Risk Engine facilitates the validation of new AVSs. Through this validation, it collects critical data on slashing risks and analyzes them to obtain actionable insights for the restakers.

#### Risk Research&#x20;

The Affine team of quantitative specialists has developed expertise in performing comprehensive risk analysis for on-chain activities, including early AVSs. The team has published a research paper on AVS yields and risks. The insights from this paper reveal how Sharpe ratios can reach equilibrium, highlighting the importance of a robust risk engine.

Check the research paper:

{% file src="/files/b7zyUexdw4TUi5fY5fah" %}
Affine Risk Engine
{% endfile %}


# ultraETH and ultraETHs

**ultraETH** represents the Liquid Restaking Token of the EigenLayer ecosystem, whereas **ultraETHs** is the corresponding token for the Symbiotic ecosystem. Restakers are given the flexibility to select their preferred ecosystem, whether it is EigenLayer or Symbiotic, for the purpose of restaking.

### Building blocks of ultraETH&#x20;

ultraETH is built on three premises-&#x20;

1. Providing liquidity to the illiquid stETH on Eigenlayer (currently valued at more than $3 billion)
2. Providing instant onboarding and fastest (7-day) offboarding for the stETH&#x20;
3. Validating early AVSs to assess their risks and share risk management models with the broader restaking community.&#x20;

Affine Labs will act as a research hub to actively share its findings about the early AVSs with the broader Eigenlayer restaker community. &#x20;

### Pricing of ultraLRT

The valuation of ultraETH shares is contingent upon the cumulative stETH holdings within the vault, deployed on EigenLayer or Symbiotic, and the forthcoming rewards gauged by oracle feeds, divided by the total ultraETH supply.

ultraETH does not incorporate a rebasing mechanism. Instead, fluctuations in share price are influenced by the aggregation of validation rewards and penalties, resulting in corresponding rises and falls.&#x20;

### Obtaining the LRTs

Users can obtain ultraETH by depositing stETH on the dApp. Please look into the [Using the Protocol](/product-walkthrough/using-the-protocol) page to learn how to restake with Affine and obtain ultraETH or ultraETHs.&#x20;

Alternatively, UltraETH can be procured from secondary DeFi markets. Please look into[Integrations and Ecosystem](/integrations-and-ecosystem/ecosystem-partners) to learn about it.


# Undiluted AVS Rewards

While many other LRTs are focusing on maximizing their TVL, Affine is committed to offering undiluted AVS Rewards to our users and grow with our partner AVSs' crypto-economic security demand. On top of [Affine ultraPoints](/product-walkthrough/affine-ultrapoints), Eigenlayer / Symbiotic Points, Affine users will earn any future airdrops or pointdrops from partner AVSs.&#x20;

In addion, we focus on being maximally transparent about these drops, we can ensure much higher allocation compared to other TVL behemoth LRTs. Especially given the current landscape of low crypto-economic security demand, as an upstart LRT we are in a position to offer much higher AVS specific yield vs major LRTs dilluting those rewards across a much larger size of TVL.

| LRT       | Total TVL\* | AVS Demand | 50 AVS APY |
| --------- | ----------- | ---------- | ---------- |
| Affine    | 100K ETH\*  | 100K ETH   | 50%        |
| Major LRT | 1M ETH      | 100K ETH   | 5%         |

\*hypothetical case where Affine has 100K ETH TVL and validating 50 AVS (each providing 1% APY) with collective 100K ETH demand. In this case, Affine is able to generate 10x more AVS yield, on top of staking yield (3-4%) and other rewards provided to the affine community.


# Using the Protocol

This guide is dedicated to providing information about the ultraETH testnet, including the staking process and using the stETH migration tool.

{% content-ref url="/pages/y1Avl6NCHzJptuYw1Bny" %}
[Restaking Walkthrough](/product-walkthrough/using-the-protocol/restaking-walkthrough)
{% endcontent-ref %}

{% content-ref url="/pages/BvgF9lQPrR8JSRjRFQPM" %}
[stETH Migration Tool](/product-walkthrough/using-the-protocol/steth-migration-tool)
{% endcontent-ref %}


# Restaking Walkthrough

You can choose your preferred ecosystem to restake on by clicking on EigenLayer or Symbiotic Logo.&#x20;

1. Go to <https://app.affinedefi.com/restake>&#x20;

<figure><img src="/files/FQ1eyJKBu0oeRxMintIW" alt=""><figcaption></figcaption></figure>

2. Connect your wallet.&#x20;
3. You should see your balance on the dApp, right on top of "Enter Amount" box.&#x20;

<figure><img src="/files/FQ1eyJKBu0oeRxMintIW" alt=""><figcaption></figcaption></figure>

4. Enter the amount you want to stake and click on "Restake." Then, approve the transaction on Metamask.&#x20;


# stETH Migration Tool

#### What stETH Migration Tool

The stETH Migration tool is designed to streamline the onboarding process of already restaked illiquid stETH. The migration tool is only available for stETH (EigenLayer).

Currently, the market cap of illiquid restaked stETH on EigenLayer stands at $3.1 billion. By issuing ultraETH against restaked stETH, it enhances liquidity and accessibility, making it easier for users to manage and increasing the usability of their restaked assets.&#x20;

#### How to use stETH Migration Tool

The stETH Migration tool allows users currently restaking with stETH to move their restaked stETH to ultraETH without losing any EigenLayer points. It is a one-stop solution to make the existing illiquid stETH liquid.&#x20;

1. On [https://app.affinedefi.com ](https://app.affinedefi.com/restake)scroll down and click on "Check if you qualify" button. Or go to <https://app.affinedefi.com/restake/migrate>

<figure><img src="/files/crO1uI7OjYyUROYeqZUj" alt=""><figcaption></figcaption></figure>

2. It will show your total stETH amount restaked on EigenLayer as "Total Unstakable Tokens."&#x20;

<figure><img src="/files/hRyGxG1wAd7eusOzPDk0" alt=""><figcaption></figcaption></figure>

3. You can put the amount you want to unstake.&#x20;
4. Click on "Unstake" to start the migration of the tokens to ultraETH.&#x20;

EigenLayer currently has a 7-day escrow period during which it holds the restaked stETH once the unstaking is requested. Then after 7 days you will need to click on Restake to receive ultraETH.&#x20;


# How to Withdraw

### How to Withdraw

If you wish to unstake, simply go to the Withdraw tab and put the amount of ultraETH you want to withdraw-&#x20;

Withdrawals from the Affine Restaking Protocol is simple a one-step process that includes redeeming the ultraETH for its corresponding stETH value. Currently, the withdrawal can take up to 7 days (the fastest in the market). The withdrawal process calls for a few steps under the hood.&#x20;

#### Step 1: Transmitting to ultraETH's Coordinator contract&#x20;

Initially, users initialize their withdrawals by transmitting a transaction to the Coordinator contract, specifying the amount of LRT (ultraETH) they wish to withdraw. If the wallet holds the specified amount of ultraETH, the coordinator contract sends the request to Eigenlayer.

#### Step 2: Eigenlayer Processing&#x20;

EigenLayer imposes a 7-day escrow period on withdrawals. This delay is necessary because the restaked tokens are utilized by operators on EigenLayer to secure Actively Validated Services.&#x20;

#### Step 3: Affine sends the stETH to the restaker

To ensure fairness in pricing, the burning of LRT (ultraETH) only occurs once the underlying asset (ETH) becomes available for withdrawal. Consequently, LRT continues to accrue rewards until the epoch settles. Meaning, the restaker will continue earning both ultraPoints and Eigenlayer Points till Affine sends out the stETH back to the users wallets.

<br>


# FAQ

#### Do I need to hold 32 ETH worth of stETH in order to restake with Affine?

&#x20; No, you can restake any amount of stETH using ultraETH.

#### Where does yield on Affine come from?

&#x20;Currently, staking yield is sourced from ETH validators. As AVSs go live on EigenLayer, Affine will work with the AVSs to ensure maximum airdrops for our users with partnerships.

#### Who’s running the ETH Validators?

&#x20;Affine has partnered with several leading operators including P2P.org, InfStone,  Luganodes, blockscape, NodeOps, who operate institutional grade nodes on Ethereum, generating Ethereum rewards.

#### How is the stETH to ultraETH Exchange Rate calculated?

ETH staking rewards and restaking rewards are accrued by the protocol. The summation of rewards and principal stETH amount (subject to slashing) is divided by the total supply of ultraETH,  influencing the price of ultraETH.

#### What can you do with ultraETH?

&#x20;You can hold ultraETH in your wallet for rewards, trade or provide liquidity on DEXs, and engage in DeFi opportunities as ultraETH integrates into more protocols.

#### If I swap my ultraETH into other ERC-20 tokens, do I still earn both EigenLayer and Affine points?

No, you need to hold ultraETH to accumulate associated rewards, except when holding LP tokens representing ultraETH. Rewards are tied directly to ultraETH.

#### Is there slashing risk for any stETH deposited into Affine?

Currently, slashing is not activated on Eigenlayer. Once it activates, ultraETH will be subjected to slashing according to the conditions set by Eigenlayer and the AVSs.&#x20;

#### Are ultraETH restakers eligible to receive airdrops from AVSs?&#x20;

Yes, if Affine users are eligible for AVS airdrops, they will receive the full proceeds. Affine will not address 3rd party airdrop queries in their channels, urging users to inquire in the relevant project channels.

### Caps & Points

#### Does EigenLayer have caps on deposits?

&#x20;There is no cap on deposits.

#### What are EigenLayer Restaked Points?

These points gauge your contribution to EigenLayer's collective security. More details can be found in EigenLayer's documentation.

#### Will users earn EigenLayer Restaked Points by restaking stETH?

&#x20;Yes, Affine allocates 100% of all EigenLayer Restaked Points to users.

#### How are Restaked Points from EigenLayer distributed?

EigenLayer Points are entirely distributed to ultraETH holders without any fees or use as collateral within Affine.

#### Does Affine charge fees on EigenLayer Restaked Points?

No, Affine directs 100% of EigenLayer Restaked Points to its users. Note that due to the technical process of native ETH staking, EigenLayer points begin accumulating approximately 24 hours after receiving ultraETH, both for minting and transferring.

#### When I restake with Affine, will I see my EigenPoints on Eigenlayer directly?

With Affine, your stETH deposits are staked with P2P in batches of 32 ETH and then restaked via EigenPods. Therefore, individual EigenLayer Pt wallet balances cannot be viewed on the EigenLayer Dapp.

### Symbiotic FAQ (coming soon)

<br>


# Affine ultraPoints

The protocol is commencing a new points reward system for the ultraETH holders. Based on the ETH value of the ultraETH held, the users can earn ultraPoints.&#x20;

#### ultraPoints Calculation (Season 1: Limited Time)

<table><thead><tr><th width="215">Type</th><th>Description </th></tr></thead><tbody><tr><td>ultraPoints</td><td>1 point per ETH per hour</td></tr><tr><td>Eigenlayer Points</td><td>1 point per ETH per hour (but will start receiving it after 24h of deposit)</td></tr><tr><td>Symbiotic Points</td><td>0.00025 points/hour per USD worth of Assets</td></tr><tr><td>NFT Multiplier</td><td>1 + log10000(1 + n) [max 1.2x]. <br>here, n = number of NFTs the user holds</td></tr><tr><td>Migration Multiplier</td><td>2x  ultraPoints for the first week </td></tr><tr><td>Layer 2 Multiplier <br>(holding ultraETHs on Blast)</td><td>1.2x ultraPoints </td></tr><tr><td>Referral Bonus</td><td>both referrer and user will get 10% extra points</td></tr><tr><td>Symbiotic Multiplier</td><td>1.5x ultraPoints till the asset is in the queue<br>1x ultraPoints when the asset is in the queue</td></tr><tr><td>DeFi Boosts</td><td><a data-mention href="/pages/059RJvpIVRDJ2j93OYR7">/pages/059RJvpIVRDJ2j93OYR7</a></td></tr></tbody></table>

#### Stage Boost&#x20;

Season 1 is divided into 4 stages to reward early users with extra ultraPoints boost. The stage boost is divided into 4 periods/TVL limit! All the users within this time period/TVL limit will earn the Stage Boost.&#x20;

<table><thead><tr><th width="468">Stage </th><th>ultraPoint Boost</th></tr></thead><tbody><tr><td>Stage 1: Till 1,000ETH TVL or Till September 15</td><td>2x</td></tr><tr><td>Stage 2: Till 5,000ETH TVL or Till October 15</td><td>1.5x</td></tr><tr><td>Stage 3: Till 10,000 ETH TVL or Till December 1</td><td>1.2x</td></tr><tr><td>Stage 4: Till End of Season 1</td><td>1x </td></tr></tbody></table>

{% hint style="info" %}
**Example 1:** \
**If someone deposits 1 ETH on ETH Mainnet August 25, 2024, and has 1 Affine Pass NFT. They will earn = 2 (Stage Boost) \* 1.075 (NFT Boost) \* 1 (Base ultraPoint amount) = 2.15 ultraPoints every hour.**&#x20;
{% endhint %}

{% hint style="info" %}
**Example 2:** \
**If someone deposits 1 ETH on ETH Mainnet September 25, 2024, and has 0 Affine Pass NFT. They will earn = 1.5 (Stage Boost) \* 1 (NFT Boost) \* 1 (Base ultraPoint amount) = 1.5 ultraPoints every hour.**&#x20;
{% endhint %}

{% hint style="info" %}
**Example 3:** \
**If someone deposits 1.5 ETH on ETH Mainnet October 25, 2024, and has 2 Affine Pass NFT. They will earn = 1.2 (Stage Boost) \* 1.12 (NFT Boost) \* 1.5 (Base ultraPoint amount) = 2.016 ultraPoints every hour.**&#x20;
{% endhint %}

<br>


# Points, Rewards, and Incentives

This document gives a short walkthrough on how to maximize rewards for ultraETH and ultraETHs Holders.

## Base ultraPoints

ultraPoints are meant to reward the users who contribute to the success of the protocol. Users earn 1 ultraPoint per ETH per hour of holding! You can learn more about the ultraPoints and basic boosts on [Affine ultraPoints](/product-walkthrough/affine-ultrapoints)page.&#x20;

However, there are options to boost your ultraPoints and earn additional rewards (CRV and BAL Tokens, Blast Gold, Thruster Credits etc.) by participating in different partner protocol programs!&#x20;

## Maximizing Points, and Rewards

### Ethereum Mainnet

**As holders of ultraETH and ultraETHs on Mainnet, you can use the following protocols to boost your ultraPoints and earn additional rewards.** &#x20;

| Actions                                       | ultraPoints    | Additional Points / Rewards                                                |
| --------------------------------------------- | -------------- | -------------------------------------------------------------------------- |
| Restake on Mainnet to receive ultraLRT        | 1x ultraPoints | <p>1x EigenLayer Point, or <br>1x Symbiotic Point</p>                      |
| Deposit Mainnet ultraLRT on **Curve Pool**    | 3x ultraPoints | <p>CRV Token Emission<br>1x EigenLayer Point, <br>1x Symbiotic Point</p>   |
| Deposit Mainnet ultraLRT on **Balancer Pool** | 3x ultraPoints | <p>BAL Token Emission<br>1x EigenLayer Point, <br>1x Symbiotic Point, </p> |

### Blast Chain (Layer 2)

ultraETHs is now launched on Blast chain. You can bridge your ultraETHs to Blast chain to receive additional ultraPoints boost and participate in different partner protocols to boost your rewards even more!&#x20;

<table><thead><tr><th width="157">Partner</th><th width="261">Actions</th><th width="185">ultraPoints </th><th>Additional Rewards </th></tr></thead><tbody><tr><td><strong>Blast</strong></td><td>Bridge ultraETHs to <strong>Blast</strong></td><td>1.2x ultraPoints </td><td><ul><li>1x Symbiotic Point</li><li>Blast Gold</li></ul></td></tr><tr><td><strong>Thruster</strong></td><td>Deposit Blast ultraETHs in <strong>Thruster</strong> Pool to receive LP Tokens</td><td>3x ultraPoints <br>Total = 1.2 * 3 = 3.6x Boost</td><td><ul><li>Thruster Credit </li><li>1x Symbiotic Point</li></ul></td></tr><tr><td><strong>Hyperlock</strong></td><td>Deposit LP tokens from Thruster on <strong>Hyperlock</strong> </td><td>3x ultraPoints <br>Total = 1.2 * 3 = 3.6x Boost</td><td><ul><li>Blast Gold</li><li>Hyperlock Points</li><li>Turtle Club Points</li><li>1x Symbiotic Point</li></ul></td></tr><tr><td><strong>Particle</strong></td><td>Deposit single-sided ultraETHs into <strong>Particle</strong></td><td>2x ultraPoints <br>Total = 1.2 * 2 = 2.4x Boost</td><td><ul><li>Blast Gold</li><li>Particle Points</li><li>1x Symbiotic Point</li></ul></td></tr><tr><td><strong>Orbit</strong> </td><td>Supply ultraETHs to borrow other assets on <strong>Orbit Lending</strong></td><td>2x ultraPoints <br>Total = 1.2 * 2 = 2.4x Boost</td><td><ul><li>Blast Gold</li><li>$ORBIT </li><li>1x Symbiotic Point</li></ul></td></tr></tbody></table>

#### Blast Gold

**Blast has allocated 100k Blast Gold to Affine. We will be distributing 100% of them to our users who hold ultraETHs on Blast.** &#x20;

### Linea Chain (Layer 2)

ultraETHs is now launched on Linea. You can restake your ETH assets natively on Linea or bridge your ultraETHs to Linea chain to receive additional ultraPoints boost and participate in different partner protocols to boost your rewards even more!&#x20;

<table><thead><tr><th width="158">Partner</th><th width="241">Action</th><th width="158">ultraPoint Boost</th><th>Additional Rewards</th></tr></thead><tbody><tr><td><strong>Linea</strong></td><td><ul><li>Restake ETH assets natively on Linea </li><li>Bridge existing ultraETHs to Linea</li></ul></td><td>1.2x </td><td><ul><li>1x Symbiotic Points </li><li>1x Turtle Club Points </li><li>LXP-L Points</li></ul></td></tr><tr><td><strong>Nile</strong></td><td><ul><li>Provide liquidity to ultraETHs &#x3C;> WETH pool on NIle</li></ul></td><td>1.2 * 3 = 3.6x </td><td><ul><li>1x Symbiotic Points </li><li>1x Turtle Club Points </li><li>LXP-L Points </li><li>Nile Turtle Points</li><li>$NILE Emission </li></ul></td></tr><tr><td><strong>Zerolend</strong></td><td><ul><li>Borrow against ultraETHs on Zerolend </li></ul></td><td>1.2 * 3 = 3.6x </td><td><p></p><ul><li>1x Symbiotic Points</li><li>1x Turtle Club Points </li><li>LXP-L Points </li><li>Zerolend Turtle Points</li><li>Gravity Points </li></ul></td></tr></tbody></table>

### Taiko Chain (Layer 2)

ultraETHs is now launched on [Taiko](https://taiko.xyz/). You can bride your ultraETHs to Taiko chain to receive additional ultraPoints boost and participate in different partner protocols to boost your rewards even more! (upcoming)

| Partner      | Action                         | ultraPoint Boost | Additional Rewards |
| ------------ | ------------------------------ | ---------------- | ------------------ |
| **Taiko**    | Bridge your ultraETHs to Taiko | 1.6x             | NA                 |
| **Izumi**    | provide liquidity              | 3x               | NA                 |
| **DTX**      | upcoming                       | x                | x                  |
| **Meridian** | upcoming                       | x                | x                  |

### NFT Boost

**You can even further boost your ultraPoints by holding Affine Pass NFT in your wallet**&#x20;

<table><thead><tr><th width="177">NFT </th><th>ultraPoints Boost</th><th>How to get?</th></tr></thead><tbody><tr><td><strong>Affine Pass NFT</strong></td><td>1 + log10000(1 + n) [max 1.2x]. <br><br>here, n = number of NFTs the user holds</td><td>Buy here: <a href="https://opensea.io/collection/affine-pass">https://opensea.io/collection/affine-pass</a></td></tr></tbody></table>

More integrations are upcoming!&#x20;

{% hint style="info" %}
**Example 1:** \
**If someone deposits 1 ETH for ultraETHs on ETH Mainnet August 25, 2024, and has 1 Affine Pass NFT. And bridges the ultraETHs to Blast.** \
\
**They will earn = 2 (Stage Boost) \* 1.075 (NFT Boost) \* 1.2 (Blast Chain Boost) \* 1 (Base ultraPoint amount) = 2.58 ultraPoints every hour.**&#x20;
{% endhint %}

{% hint style="info" %}
**Example 2:** \
**If someone deposits 1 ETH for ultraETHs on ETH Mainnet August 25, 2024, and has 1 Affine Pass NFT.** \
**Then, they bridges the ultraETHs to Blast, and uses those ultraETHs to stake on Thruster** \
**and stakes the LP tokens in Hyperlock.**\
\
**They will earn = 2 (Stage Boost) \* 1.075 (NFT Boost) \* 1.2 (Blast Chain Boost) \* 3 (Thruster Boost) \* 1 (Base ultraPoint amount) = 7.74 ultraPoints every hour.**  \
\
**Please note: They would earn 7.74 ultraPoints, even if he chose not to use Hyperlock. However, using Hyperlock makes him eligible for Blast Gold, Hyperlock Points, and Turtle Club Points**
{% endhint %}

{% hint style="info" %}
**Example 3:** \
**If someone deposits 1 ETH for ultraETHs on ETH Mainnet September 25, 2024, and has 1 Affine Pass NFT. Then bridges the ultraETHs to Blast. And then uses that ultraETHs to deposit into Particle.** \
\
**They will earn = 2 (Stage Boost) \* 1.075 (NFT Boost) \* 1.2 (Blast Chain Boost) \* 2 (Particle Boost) \* 1 (Base ultraPoint amount) = 5.16 ultraPoints every hour.**&#x20;
{% endhint %}


# Technical Architecture

ultraETH and ultraETHs, collectively ultraLRTs are liquid staking tokens on Eigenlayer and Symbiotic that allow users to deposit their staked Ethereum (stETH) and receive LRT shares in return. These shares can be redeemed for the underlying stETH at any time. The protocol consists of several key components:

### UltraLRT (Liquid Restaking Token)

The UltraLRT contract is the core of the protocol. It is an ERC-4626 vault that accepts deposits of stETH and issues shares (UltraLRT tokens) in return. The contract manages the delegation of staked assets to various delegators and handles the harvesting and distribution of rewards.

{% embed url="<https://github.com/AffineLabs/contracts/tree/ultra-lrt-v2/src/vaults/restaking>" %}
Affine ultraLRT Repo
{% endembed %}

### Flow of Fund Diagram

<figure><img src="/files/k5Wk0zAvB0GLpdLQIbPy" alt=""><figcaption></figcaption></figure>

### Key features

* Accepts deposits of stETH and issues UltraLRT shares
* Delegates staked assets to various delegators
* Harvests and distributes rewards to UltraLRT holders
* Supports withdrawal requests and debt resolution
* Implements fee management (management fee and withdrawal fee)

### Delegators

Delegators are contracts responsible for delegating and restaking the staked assets on different liquid staking protocols like Eigenlayer and Symbiotic. The protocol supports two types of delegators:

1. **EigenDelegator**: Delegates and restakes stETH on the Eigenlayer protocol.
2. **SymbioticDelegator**: Delegates and restakes wstETH (wrapped stETH) on the Symbiotic protocol.

These delegators interact with the respective protocols to delegate the staked assets and manage withdrawal requests.

### Factories and Beacons

The protocol uses the Proxy and Beacon pattern to deploy and upgrade delegators. The following contracts are involved:

* **DelegatorBeacon**: Upgradeable beacon contract for delegators.
* **DelegatorFactory**: Factory contract for creating new delegator instances.
* **SymDelegatorFactory**: Factory contract for creating new Symbiotic delegator instances.

### WithdrawalEscrowV2

The WithdrawalEscrowV2 contract handles withdrawal requests from users. It registers withdrawal requests as debt and manages the resolution of debt shares when assets become available.

### UltraLRTRouter

The UltraLRTRouter contract facilitates deposits into the UltraLRT vault. It supports deposits of native ETH, WETH, stETH, and wstETH by wrapping/unwrapping the assets as needed.

### Other Contracts

* **AffineReStaking**: A contract for managing deposits and withdrawals of various approved tokens.
* **AffineDelegator**: An abstract contract that defines the interface for delegators.
* **UltraLRTStorage**: A storage contract for the UltraLRT contract.

### Key Interfaces

* **IDelegator**: Interface for delegator contracts.
* **IDelegatorBeacon**: Interface for the delegator beacon contract.
* **IDelegatorFactory**: Interface for the delegator factory contract.

This codebase implements a liquid staking protocol that allows users to stake their Ethereum and receive liquid shares in return. The protocol leverages various liquid staking protocols like Eigenlayer and Symbiotic to delegate and restake the staked assets. It provides a unified interface for users to deposit, withdraw, and manage their liquid staking positions.

### Additional Resources

1. To learn how to compile and run this code base read this repo home documentation
2. Auto-generated technical documentations
3. [General user facing documentation](https://affinedefi.gitbook.io/affine-ultraeth)

Report any issues or bug on [Affine discord](https://discord.com/invite/RvSFFfUdvX)


# Source Code Docs

{% embed url="<https://github.com/AffineLabs/contracts/tree/ultra-lrt-v2/src/vaults/restaking>" %}

### IUltraLRT

#### hasRole

```solidity
function hasRole(bytes32 role, address user) external view returns (bool)
```

#### HARVESTER

```solidity
function HARVESTER() external view returns (bytes32)
```

### AffineDelegator

*Delegator contract for stETH on Eigenlayer*

#### vault

```solidity
address vault
```

#### asset

```solidity
contract ERC20 asset
```

#### onlyVaultOrHarvester

```solidity
modifier onlyVaultOrHarvester()
```

Modifier to allow function calls only from the vault or harvester

#### onlyVault

```solidity
modifier onlyVault()
```

Modifier to allow function calls only from the vault

#### onlyHarvester

```solidity
modifier onlyHarvester()
```

Modifier to allow function calls only from the harvester

#### delegate

```solidity
function delegate(uint256 amount) external
```

*Delegate & restake stETH to operator*

#### \_delegate

```solidity
function _delegate(uint256 amount) internal virtual
```

*Delegate stETH to operator*

#### requestWithdrawal

```solidity
function requestWithdrawal(uint256 assets) external
```

Request withdrawal from eigenlayer

*Request withdrawal from eigenlayer*

**Parameters**

| Name   | Type    | Description        |
| ------ | ------- | ------------------ |
| assets | uint256 | Amount to withdraw |

#### \_requestWithdrawal

```solidity
function _requestWithdrawal(uint256 assets) internal virtual
```

*Request withdrawal from eigenlayer*

#### withdraw

```solidity
function withdraw() external virtual
```

*Withdraw stETH from delegator to vault*

#### totalLockedValue

```solidity
function totalLockedValue() public view virtual returns (uint256)
```

Get total locked value

**Return Values**

| Name | Type    | Description        |
| ---- | ------- | ------------------ |
| \[0] | uint256 | Total locked value |

#### withdrawableAssets

```solidity
function withdrawableAssets() public view virtual returns (uint256)
```

Get withdrawable assets

**Return Values**

| Name | Type    | Description                   |
| ---- | ------- | ----------------------------- |
| \[0] | uint256 | Amount of withdrawable assets |

#### queuedAssets

```solidity
function queuedAssets() public view virtual returns (uint256)
```

Get queued assets

**Return Values**

| Name | Type    | Description             |
| ---- | ------- | ----------------------- |
| \[0] | uint256 | Amount of queued assets |

### AffineReStaking

#### initialize

```solidity
function initialize(address _governance, address _weth) external
```

#### \_authorizeUpgrade

```solidity
function _authorizeUpgrade(address newImplementation) internal
```

\_Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by {upgradeTo} and {upgradeToAndCall}.

Normally, this function will use an xref:access.adoc\[access control] modifier such as {Ownable-onlyOwner}.

````solidity
function _authorizeUpgrade(address) internal override onlyOwner {}
```_

### GUARDIAN_ROLE

```solidity
bytes32 GUARDIAN_ROLE
````

#### APPROVED\_TOKEN

```solidity
bytes32 APPROVED_TOKEN
```

#### WETH

```solidity
contract IWETH WETH
```

#### balance

```solidity
mapping(address => mapping(address => uint256)) balance
```

#### depositPaused

```solidity
uint256 depositPaused
```

#### whenDepositNotPaused

```solidity
modifier whenDepositNotPaused()
```

#### pauseDeposit

```solidity
function pauseDeposit() external
```

#### resumeDeposit

```solidity
function resumeDeposit() external
```

#### approveToken

```solidity
function approveToken(address _token) external
```

#### revokeToken

```solidity
function revokeToken(address _token) external
```

#### Deposit

```solidity
event Deposit(uint256 eventId, address depositor, address token, uint256 amount)
```

#### depositFor

```solidity
function depositFor(address _token, address _for, uint256 _amount) external
```

#### depositETHFor

```solidity
function depositETHFor(address _for) external payable
```

#### Withdraw

```solidity
event Withdraw(uint256 eventId, address withdrawer, address token, uint256 amount)
```

#### withdraw

```solidity
function withdraw(address _token, uint256 _amount) external
```

#### pause

```solidity
function pause() external
```

Pause the contract

#### unpause

```solidity
function unpause() external
```

Unpause the contract

### IDelegatorBeacon

#### owner

```solidity
function owner() external returns (address)
```

### DelegatorBeacon

*Delegator Beacon contract*

#### beacon

```solidity
contract UpgradeableBeacon beacon
```

#### blueprint

```solidity
address blueprint
```

#### constructor

```solidity
constructor(address _initBlueprint, address governance) public
```

*Constructor*

**Parameters**

| Name            | Type    | Description               |
| --------------- | ------- | ------------------------- |
| \_initBlueprint | address | Initial blueprint address |
| governance      | address | Governance address        |

#### update

```solidity
function update(address _newBlueprint) public
```

Update the blueprint

**Parameters**

| Name           | Type    | Description           |
| -------------- | ------- | --------------------- |
| \_newBlueprint | address | New blueprint address |

#### implementation

```solidity
function implementation() public view returns (address)
```

Get the implementation address

**Return Values**

| Name | Type    | Description            |
| ---- | ------- | ---------------------- |
| \[0] | address | Implementation address |

### IDelegatorFactory

#### createDelegator

```solidity
function createDelegator(address _operator) external returns (address)
```

#### vault

```solidity
function vault() external returns (address)
```

### DelegatorFactory

*Delegator Factory contract*

#### vault

```solidity
address vault
```

#### onlyVault

```solidity
modifier onlyVault()
```

*Modifier to allow function calls only from the vault*

#### constructor

```solidity
constructor(address _vault) public
```

*Constructor*

**Parameters**

| Name    | Type    | Description   |
| ------- | ------- | ------------- |
| \_vault | address | Vault address |

#### createDelegator

```solidity
function createDelegator(address _operator) external returns (address)
```

Create a new delegator

**Parameters**

| Name       | Type    | Description      |
| ---------- | ------- | ---------------- |
| \_operator | address | Operator address |

**Return Values**

| Name | Type    | Description       |
| ---- | ------- | ----------------- |
| \[0] | address | Delegator address |

### EigenDelegator

*Delegator contract for stETH on Eigenlayer*

#### STRATEGY\_MANAGER

```solidity
contract IStrategyManager STRATEGY_MANAGER
```

StrategyManager for Eigenlayer

#### DELEGATION\_MANAGER

```solidity
contract IDelegationManager DELEGATION_MANAGER
```

DelegationManager for Eigenlayer

#### STAKED\_ETH\_STRATEGY

```solidity
contract IStrategy STAKED_ETH_STRATEGY
```

stETH strategy on Eigenlayer

#### withdrawals

```solidity
mapping(bytes32 => uint256) withdrawals
```

#### initialize

```solidity
function initialize(address _vault, address _operator) external
```

*Initialize the contract*

**Parameters**

| Name       | Type    | Description      |
| ---------- | ------- | ---------------- |
| \_vault    | address | Vault address    |
| \_operator | address | Operator address |

#### currentOperator

```solidity
address currentOperator
```

#### stETH

```solidity
contract IStEth stETH
```

#### queuedShares

```solidity
uint256 queuedShares
```

#### \_delegate

```solidity
function _delegate(uint256 amount) internal
```

Modifier to allow function calls only from the vault or harvester

*Delegate & restake stETH to operator on Eigenlayer*

**Parameters**

| Name   | Type    | Description        |
| ------ | ------- | ------------------ |
| amount | uint256 | Amount to delegate |

#### \_requestWithdrawal

```solidity
function _requestWithdrawal(uint256 assets) internal
```

Request withdrawal from eigenlayer

**Parameters**

| Name   | Type    | Description        |
| ------ | ------- | ------------------ |
| assets | uint256 | Amount to withdraw |

#### completeWithdrawalRequest

```solidity
function completeWithdrawalRequest(struct WithdrawalInfo[] withdrawalInfo) external
```

Complete withdrawal request

**Parameters**

| Name           | Type                     | Description     |
| -------------- | ------------------------ | --------------- |
| withdrawalInfo | struct WithdrawalInfo\[] | Withdrawal info |

#### recordWithdrawalsRequest

```solidity
function recordWithdrawalsRequest(struct WithdrawalInfo withdrawal) external
```

Record withdrawal request from External requests

**Parameters**

| Name       | Type                  | Description     |
| ---------- | --------------------- | --------------- |
| withdrawal | struct WithdrawalInfo | Withdrawal info |

#### withdraw

```solidity
function withdraw() external
```

*Withdraw stETH from delegator to vault*

#### withdrawableAssets

```solidity
function withdrawableAssets() public view returns (uint256)
```

Get withdrawable assets

**Return Values**

| Name | Type    | Description         |
| ---- | ------- | ------------------- |
| \[0] | uint256 | withdrawable assets |

#### queuedAssets

```solidity
function queuedAssets() public view returns (uint256)
```

Get queued assets

**Return Values**

| Name | Type    | Description   |
| ---- | ------- | ------------- |
| \[0] | uint256 | queued assets |

#### \_delegateToOperator

```solidity
function _delegateToOperator() internal
```

*Delegate to operator*

### IDelegator

#### requestWithdrawal

```solidity
function requestWithdrawal(uint256 assets) external
```

#### checkAssetAvailability

```solidity
function checkAssetAvailability(uint256 assets) external view returns (bool)
```

#### delegate

```solidity
function delegate(uint256 amount) external
```

#### withdraw

```solidity
function withdraw() external
```

#### totalLockedValue

```solidity
function totalLockedValue() external returns (uint256)
```

#### withdrawableAssets

```solidity
function withdrawableAssets() external view returns (uint256)
```

#### queuedAssets

```solidity
function queuedAssets() external view returns (uint256)
```

### SymDelegatorFactory

*SymDelegator Factory contract*

#### vault

```solidity
address vault
```

#### onlyVault

```solidity
modifier onlyVault()
```

*Modifier to allow function calls only from the vault*

#### constructor

```solidity
constructor(address _vault) public
```

*Constructor*

**Parameters**

| Name    | Type    | Description   |
| ------- | ------- | ------------- |
| \_vault | address | Vault address |

#### createDelegator

```solidity
function createDelegator(address _collateral) external returns (address proxy)
```

Create a new delegator

**Parameters**

| Name         | Type    | Description        |
| ------------ | ------- | ------------------ |
| \_collateral | address | Collateral address |

**Return Values**

| Name  | Type    | Description       |
| ----- | ------- | ----------------- |
| proxy | address | Delegator address |

### SymbioticDelegator

*Delegator contract for wStETH on Symbiotic*

#### collateral

```solidity
contract IDefaultCollateral collateral
```

#### initialize

```solidity
function initialize(address _vault, address _collateral) external
```

*Initialize the contract*

**Parameters**

| Name         | Type    | Description        |
| ------------ | ------- | ------------------ |
| \_vault      | address | Vault address      |
| \_collateral | address | Collateral address |

#### \_delegate

```solidity
function _delegate(uint256 amount) internal
```

Delegate & restake wStETH to operator on Symbiotic

**Parameters**

| Name   | Type    | Description        |
| ------ | ------- | ------------------ |
| amount | uint256 | Amount to delegate |

#### \_requestWithdrawal

```solidity
function _requestWithdrawal(uint256 assets) internal
```

Request withdrawal from Symbiotic

**Parameters**

| Name   | Type    | Description        |
| ------ | ------- | ------------------ |
| assets | uint256 | Amount to withdraw |

#### withdrawableAssets

```solidity
function withdrawableAssets() public view returns (uint256)
```

Get the withdrawable assets

**Return Values**

| Name | Type    | Description         |
| ---- | ------- | ------------------- |
| \[0] | uint256 | withdrawable assets |

#### queuedAssets

```solidity
function queuedAssets() public view returns (uint256)
```

Get the queued assets

**Return Values**

| Name | Type    | Description   |
| ---- | ------- | ------------- |
| \[0] | uint256 | queued assets |

### UltraLRT

UltraLRT is a liquid staking vault that allows users to deposit staked assets and receive shares in return. The shares can be redeemed for the underlying assets at any time. Vault will delegate the assets to the delegators and harvest the profit. The vault will also distribute the profits to the holders.

#### initialize

```solidity
function initialize(address _governance, address _asset, address _delegatorBeacon, string _name, string _symbol) external
```

Initialize the UltraLRT contract

**Parameters**

| Name              | Type    | Description                            |
| ----------------- | ------- | -------------------------------------- |
| \_governance      | address | The address of the governance contract |
| \_asset           | address | The address of the asset token         |
| \_delegatorBeacon | address | The address of the delegator beacon    |
| \_name            | string  | The name of the token                  |
| \_symbol          | string  | The symbol of the token                |

#### \_authorizeUpgrade

```solidity
function _authorizeUpgrade(address newImplementation) internal
```

Upgrade the UltraLRT contract

**Parameters**

| Name              | Type    | Description                                    |
| ----------------- | ------- | ---------------------------------------------- |
| newImplementation | address | The address of the new implementation contract |

#### maxDeposit

```solidity
function maxDeposit(address) public view virtual returns (uint256)
```

The maximum amount of assets that can be deposited into the vault

*See {IERC4262-maxDeposit}.*

**Return Values**

| Name | Type    | Description                                        |
| ---- | ------- | -------------------------------------------------- |
| \[0] | uint256 | The maximum amount of assets that can be deposited |

#### maxMint

```solidity
function maxMint(address) public view virtual returns (uint256)
```

The maximum amount of shares that can be minted

*See {IERC4262-maxMint}.*

**Return Values**

| Name | Type    | Description                                     |
| ---- | ------- | ----------------------------------------------- |
| \[0] | uint256 | The maximum amount of shares that can be minted |

#### setDelegatorFactory

```solidity
function setDelegatorFactory(address _factory) external
```

set the delegator factory

*factory must have the vault set to this vault*

**Parameters**

| Name      | Type    | Description                          |
| --------- | ------- | ------------------------------------ |
| \_factory | address | The address of the delegator factory |

#### setMaxUnresolvedEpochs

```solidity
function setMaxUnresolvedEpochs(uint256 _maxUnresolvedEpochs) external
```

set max unresolved epoch

*delegation of assets will be stopped if the unresolved epoch is greater than the max unresolved epoch*

**Parameters**

| Name                  | Type    | Description                  |
| --------------------- | ------- | ---------------------------- |
| \_maxUnresolvedEpochs | uint256 | The maximum unresolved epoch |

#### pause

```solidity
function pause() external
```

Pause the contract

#### unpause

```solidity
function unpause() external
```

Unpause the contract

#### initialSharesPerAsset

```solidity
function initialSharesPerAsset() public pure virtual returns (uint256)
```

The amount of shares to mint per wei of `asset` at genesis.

#### \_initialShareDecimals

```solidity
function _initialShareDecimals() internal pure virtual returns (uint8)
```

Each wei of `asset` at genesis is worth 10 \*\* (initialShareDecimals) shares.

#### pauseDeposit

```solidity
function pauseDeposit() external
```

Pause the deposit

#### unpauseDeposit

```solidity
function unpauseDeposit() external
```

Unpause the deposit

#### deposit

```solidity
function deposit(uint256 assets, address receiver) public returns (uint256)
```

Deposit assets into the vault

**Parameters**

| Name     | Type    | Description                 |
| -------- | ------- | --------------------------- |
| assets   | uint256 |                             |
| receiver | address | The address of the receiver |

**Return Values**

| Name | Type    | Description                 |
| ---- | ------- | --------------------------- |
| \[0] | uint256 | The amount of shares minted |

#### mint

```solidity
function mint(uint256 shares, address receiver) public returns (uint256)
```

mint specific amount of shares

**Parameters**

| Name     | Type    | Description                  |
| -------- | ------- | ---------------------------- |
| shares   | uint256 | The amount of shares to mint |
| receiver | address | The address of the receiver  |

**Return Values**

| Name | Type    | Description                 |
| ---- | ------- | --------------------------- |
| \[0] | uint256 | The amount of assets minted |

#### withdraw

```solidity
function withdraw(uint256 assets, address receiver, address owner) public returns (uint256)
```

Withdraw assets from the vault

*See {IERC4262-withdraw}.*

**Parameters**

| Name     | Type    | Description                      |
| -------- | ------- | -------------------------------- |
| assets   | uint256 | The amount of assets to withdraw |
| receiver | address | The address of the receiver      |
| owner    | address | The address of the owner         |

**Return Values**

| Name | Type    | Description                 |
| ---- | ------- | --------------------------- |
| \[0] | uint256 | The amount of shares burned |

#### redeem

```solidity
function redeem(uint256 shares, address receiver, address owner) public returns (uint256)
```

Redeem shares from the vault

*See {IERC4262-redeem}.*

**Parameters**

| Name     | Type    | Description                    |
| -------- | ------- | ------------------------------ |
| shares   | uint256 | The amount of shares to redeem |
| receiver | address | The address of the receiver    |
| owner    | address | The address of the owner       |

**Return Values**

| Name | Type    | Description                   |
| ---- | ------- | ----------------------------- |
| \[0] | uint256 | The amount of assets redeemed |

#### \_withdraw

```solidity
function _withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares) internal
```

withdraw from the vault

**Parameters**

| Name     | Type    | Description                      |
| -------- | ------- | -------------------------------- |
| caller   | address | The address of the caller        |
| receiver | address | The address of the receiver      |
| owner    | address | The address of the owner         |
| assets   | uint256 | The amount of assets to withdraw |
| shares   | uint256 | The amount of shares to burn     |

#### canWithdraw

```solidity
function canWithdraw(uint256 assets) public view returns (bool)
```

Check if the withdrawal can be done

**Parameters**

| Name   | Type    | Description                      |
| ------ | ------- | -------------------------------- |
| assets | uint256 | The amount of assets to withdraw |

**Return Values**

| Name | Type | Description                        |
| ---- | ---- | ---------------------------------- |
| \[0] | bool | True if the withdrawal can be done |

#### setWithdrawalEscrow

```solidity
function setWithdrawalEscrow(contract WithdrawalEscrowV2 _escrow) external
```

Set the withdrawal escrow

*The escrow must have the vault set to this vault @dev existing escrow debt must be zero*

**Parameters**

| Name     | Type                        | Description                          |
| -------- | --------------------------- | ------------------------------------ |
| \_escrow | contract WithdrawalEscrowV2 | The address of the withdrawal escrow |

#### endEpoch

```solidity
function endEpoch() external
```

End the current epoch

*Only the harvester can end the epoch anytime for other The epoch can only be ended if the last epoch was ended at least `LOCK_INTERVAL` seconds ago*

#### liquidationRequest

```solidity
function liquidationRequest(uint256 assets) external
```

Do liquidation request to delegators

*Only the harvester can do the liquidation request*

**Parameters**

| Name   | Type    | Description                       |
| ------ | ------- | --------------------------------- |
| assets | uint256 | The amount of assets to liquidate |

#### \_liquidationRequest

```solidity
function _liquidationRequest(uint256 assets) internal
```

Do liquidation request to delegators

**Parameters**

| Name   | Type    | Description                       |
| ------ | ------- | --------------------------------- |
| assets | uint256 | The amount of assets to liquidate |

#### delegatorWithdrawRequest

```solidity
function delegatorWithdrawRequest(contract IDelegator delegator, uint256 assets) external
```

Withdraw from speicific delegator

**Parameters**

| Name      | Type                | Description                      |
| --------- | ------------------- | -------------------------------- |
| delegator | contract IDelegator | The address of the delegator     |
| assets    | uint256             | The amount of assets to withdraw |

#### resolveDebt

```solidity
function resolveDebt() external
```

Resolve the debt

#### createDelegator

```solidity
function createDelegator(address _operator) external
```

Create a new delegator

**Parameters**

| Name       | Type    | Description                 |
| ---------- | ------- | --------------------------- |
| \_operator | address | The address of the operator |

#### dropDelegator

```solidity
function dropDelegator(address _delegator) external
```

Drop a delegator

**Parameters**

| Name        | Type    | Description                  |
| ----------- | ------- | ---------------------------- |
| \_delegator | address | The address of the delegator |

#### harvest

```solidity
function harvest() external
```

Harvest the profit

#### collectDelegatorDebt

```solidity
function collectDelegatorDebt() external
```

Collect the delegator debt

*will withdraw the liquid assets from the delegators*

#### withdrawFromDelegator

```solidity
function withdrawFromDelegator(address _delegator) external
```

TODO check for price change on profit and loss

#### \_getDelegatorLiquidAssets

```solidity
function _getDelegatorLiquidAssets(uint256 requiredVaultAssets) internal
```

Get the delegator liquid assets

*Each time this will check the vault assets, if it meets required assets then it will stop*

**Parameters**

| Name                | Type    | Description                                   |
| ------------------- | ------- | --------------------------------------------- |
| requiredVaultAssets | uint256 | The amount of liquid assets required in vault |

#### delegateToDelegator

```solidity
function delegateToDelegator(address _delegator, uint256 amount) external
```

Delegate the assets to the delegator

**Parameters**

| Name        | Type    | Description                      |
| ----------- | ------- | -------------------------------- |
| \_delegator | address | The address of the delegator     |
| amount      | uint256 | The amount of assets to delegate |

#### lockedProfit

```solidity
function lockedProfit() public view virtual returns (uint256)
```

Current locked profit amount.

*Profit unlocks uniformly over `LOCK_INTERVAL` seconds after the last harvest*

#### totalAssets

```solidity
function totalAssets() public view returns (uint256)
```

Get the total assets

#### vaultAssets

```solidity
function vaultAssets() public view returns (uint256)
```

Get the vault liquid assets

#### setManagementFee

```solidity
function setManagementFee(uint256 feeBps) external
```

Set the management fee

#### setWithdrawalFee

```solidity
function setWithdrawalFee(uint256 feeBps) external
```

Set the withdrawal fee

#### getRate

```solidity
function getRate() external view returns (uint256)
```

returns the per share assets

### UltraLRTRouter

*handle deposits from native, weth, stEth, wStEth to vaults*

#### weth

```solidity
contract IWETH weth
```

#### stEth

```solidity
contract IStEth stEth
```

#### wStEth

```solidity
contract IWSTETH wStEth
```

#### permit2

```solidity
contract IPermit2 permit2
```

#### initialize

```solidity
function initialize(address _governance, address _weth, address _stEth, address _wStEth, address _permit2) external
```

*Initialize the contract*

**Parameters**

| Name         | Type    | Description        |
| ------------ | ------- | ------------------ |
| \_governance | address | Governance address |
| \_weth       | address | WETH address       |
| \_stEth      | address | stETH address      |
| \_wStEth     | address | wstETH address     |
| \_permit2    | address | Permit2 address    |

#### \_authorizeUpgrade

```solidity
function _authorizeUpgrade(address newImplementation) internal
```

*Upgrade the contract*

**Parameters**

| Name              | Type    | Description                |
| ----------------- | ------- | -------------------------- |
| newImplementation | address | New implementation address |

#### pause

```solidity
function pause() external
```

Pause the contract

#### unpause

```solidity
function unpause() external
```

Unpause the contract

#### receive

```solidity
receive() external payable
```

Fallback function to receive native tokens

#### depositNative

```solidity
function depositNative(address vault, address to) public payable
```

Deposit native tokens to vault

**Parameters**

| Name  | Type    | Description      |
| ----- | ------- | ---------------- |
| vault | address | Vault address    |
| to    | address | Receiver address |

#### \_processNativeDeposit

```solidity
function _processNativeDeposit(uint256 amount, address vault, address to) internal
```

Deposit native tokens to vault

**Parameters**

| Name   | Type    | Description       |
| ------ | ------- | ----------------- |
| amount | uint256 | Amount to deposit |
| vault  | address | Vault address     |
| to     | address | Receiver address  |

#### \_receiveAssetFromThroughPermit2

```solidity
function _receiveAssetFromThroughPermit2(address token, uint256 amount, uint256 nonce, uint256 deadline, bytes signature) internal
```

Receive asset from user through permit2

**Parameters**

| Name      | Type    | Description                       |
| --------- | ------- | --------------------------------- |
| token     | address | Token address                     |
| amount    | uint256 | Amount to receive                 |
| nonce     | uint256 | Nonce                             |
| deadline  | uint256 | Deadline of the permit2 approval  |
| signature | bytes   | Signature of the permit2 approval |

#### depositWeth

```solidity
function depositWeth(uint256 amount, address vault, address to, uint256 nonce, uint256 deadline, bytes signature) external
```

Deposit WETH to vault

**Parameters**

| Name      | Type    | Description                       |
| --------- | ------- | --------------------------------- |
| amount    | uint256 | Amount to deposit                 |
| vault     | address | Vault address                     |
| to        | address | Receiver address                  |
| nonce     | uint256 | Nonce                             |
| deadline  | uint256 | Deadline of the permit2 approval  |
| signature | bytes   | Signature of the permit2 approval |

#### depositStEth

```solidity
function depositStEth(uint256 amount, address vault, address to, uint256 nonce, uint256 deadline, bytes signature) external
```

Deposit stETH to vault

**Parameters**

| Name      | Type    | Description                       |
| --------- | ------- | --------------------------------- |
| amount    | uint256 | Amount to deposit                 |
| vault     | address | Vault address                     |
| to        | address | Receiver address                  |
| nonce     | uint256 | Nonce                             |
| deadline  | uint256 | Deadline of the permit2 approval  |
| signature | bytes   | Signature of the permit2 approval |

#### depositWStEth

```solidity
function depositWStEth(uint256 amount, address vault, address to, uint256 nonce, uint256 deadline, bytes signature) external
```

Deposit wStETH to vault

**Parameters**

| Name      | Type    | Description                       |
| --------- | ------- | --------------------------------- |
| amount    | uint256 | Amount to deposit                 |
| vault     | address | Vault address                     |
| to        | address | Receiver address                  |
| nonce     | uint256 | Nonce                             |
| deadline  | uint256 | Deadline of the permit2 approval  |
| signature | bytes   | Signature of the permit2 approval |

#### \_processDepositFromStEth

```solidity
function _processDepositFromStEth(uint256 amount, address vault, address to) internal
```

Process deposit from stEth

**Parameters**

| Name   | Type    | Description       |
| ------ | ------- | ----------------- |
| amount | uint256 | Amount to deposit |
| vault  | address | Vault address     |
| to     | address | Receiver address  |

#### \_depositStEthToVault

```solidity
function _depositStEthToVault(uint256 amount, address vault, address to) internal
```

Deposit stEth to vault

**Parameters**

| Name   | Type    | Description       |
| ------ | ------- | ----------------- |
| amount | uint256 | Amount to deposit |
| vault  | address | Vault address     |
| to     | address | Receiver address  |

#### \_depositWStEthToVault

```solidity
function _depositWStEthToVault(uint256 amount, address vault, address to) internal
```

Deposit wStEth to vault

**Parameters**

| Name   | Type    | Description       |
| ------ | ------- | ----------------- |
| amount | uint256 | Amount to deposit |
| vault  | address | Vault address     |
| to     | address | Receiver address  |

### UltraLRTStorage

#### DelegatorInfo

```solidity
struct DelegatorInfo {
  bool isActive;
  uint248 balance;
}
```

#### GUARDIAN\_ROLE

```solidity
bytes32 GUARDIAN_ROLE
```

#### HARVESTER

```solidity
bytes32 HARVESTER
```

#### MAX\_BPS

```solidity
uint256 MAX_BPS
```

#### MAX\_DELEGATOR

```solidity
uint256 MAX_DELEGATOR
```

#### ST\_ETH\_TRANSFER\_BUFFER

```solidity
uint256 ST_ETH_TRANSFER_BUFFER
```

#### depositPaused

```solidity
uint256 depositPaused
```

#### STETH

```solidity
contract IStEth STETH
```

#### escrow

```solidity
contract WithdrawalEscrowV2 escrow
```

#### beacon

```solidity
address beacon
```

#### delegatorFactory

```solidity
address delegatorFactory
```

#### delegatorAssets

```solidity
uint256 delegatorAssets
```

#### managementFee

```solidity
uint256 managementFee
```

Fee charged to vault over a year, number is in bps

#### withdrawalFee

```solidity
uint256 withdrawalFee
```

Fee charged on redemption of shares, number is in bps

#### lastHarvest

```solidity
uint256 lastHarvest
```

A timestamp representing when the most recent harvest occurred.

*Since the time since the last harvest is used to calculate management fees, this is set to `block.timestamp` (instead of 0) during initialization.*

#### maxLockedProfit

```solidity
uint256 maxLockedProfit
```

The amount of profit *originally* locked after harvesting from a strategy

#### LOCK\_INTERVAL

```solidity
uint256 LOCK_INTERVAL
```

Amount of time in seconds that profit takes to fully unlock. See lockedProfit().

#### delegatorQueue

```solidity
contract IDelegator[50] delegatorQueue
```

#### delegatorMap

```solidity
mapping(address => struct UltraLRTStorage.DelegatorInfo) delegatorMap
```

#### delegatorCount

```solidity
uint256 delegatorCount
```

#### lastEpochTime

```solidity
uint256 lastEpochTime
```

#### maxUnresolvedEpochs

```solidity
uint256 maxUnresolvedEpochs
```

#### whenDepositNotPaused

```solidity
modifier whenDepositNotPaused()
```

### WithdrawalEscrowV2

*Escrow contract for withdrawal requests*

#### asset

```solidity
contract ERC20 asset
```

The vault asset.

#### vault

```solidity
contract UltraLRT vault
```

The vault this escrow attached to.

#### userDebtShare

```solidity
mapping(uint256 => mapping(address => uint256)) userDebtShare
```

#### EpochInfo

```solidity
struct EpochInfo {
  uint128 shares;
  uint128 assets;
}
```

#### currentEpoch

```solidity
uint256 currentEpoch
```

#### resolvingEpoch

```solidity
uint256 resolvingEpoch
```

#### totalDebt

```solidity
uint256 totalDebt
```

#### epochInfo

```solidity
mapping(uint256 => struct WithdrawalEscrowV2.EpochInfo) epochInfo
```

#### constructor

```solidity
constructor(contract UltraLRT _vault) public
```

**Parameters**

| Name    | Type              | Description            |
| ------- | ----------------- | ---------------------- |
| \_vault | contract UltraLRT | UltraLRT vault address |

#### onlyVault

```solidity
modifier onlyVault()
```

Modifier to allow function calls only from the vault

#### onlyGovernance

```solidity
modifier onlyGovernance()
```

Modifier to allow function calls only from the governance

#### WithdrawalRequest

```solidity
event WithdrawalRequest(address user, uint256 epoch, uint256 shares)
```

Withdrawal Request event

*will makes things easy to search for each user withdrawal requests*

**Parameters**

| Name   | Type    | Description             |
| ------ | ------- | ----------------------- |
| user   | address | user address            |
| epoch  | uint256 | epoch of the request    |
| shares | uint256 | withdrawal vault shares |

#### registerWithdrawalRequest

```solidity
function registerWithdrawalRequest(address user, uint256 shares) external
```

Register withdrawal request as debt

**Parameters**

| Name   | Type    | Description                                       |
| ------ | ------- | ------------------------------------------------- |
| user   | address | user address                                      |
| shares | uint256 | amount of vault shares user requested to withdraw |

#### endEpoch

```solidity
function endEpoch() external
```

End the epoch

*will be called by the vault after closing a position*

#### getDebtToResolve

```solidity
function getDebtToResolve() external view returns (uint256)
```

Get the debt to resolve

**Return Values**

| Name | Type    | Description               |
| ---- | ------- | ------------------------- |
| \[0] | uint256 | amount of debt to resolve |

#### resolveDebtShares

```solidity
function resolveDebtShares() external
```

resolve the locked shares for current epoch

*This function will be triggered after closing a position will check for available shares to burn after resolving vault will send the assets to escrow and burn the share*

#### redeemMultiEpoch

```solidity
function redeemMultiEpoch(address user, uint256[] epochs) public returns (uint256 totalAssets)
```

Redeem multiple epochs

**Parameters**

| Name   | Type       | Description               |
| ------ | ---------- | ------------------------- |
| user   | address    | user address              |
| epochs | uint256\[] | withdrawal request epochs |

**Return Values**

| Name        | Type    | Description |
| ----------- | ------- | ----------- |
| totalAssets | uint256 | received    |

#### redeem

```solidity
function redeem(address user, uint256 epoch) public returns (uint256)
```

Redeem withdrawal request

**Parameters**

| Name  | Type    | Description              |
| ----- | ------- | ------------------------ |
| user  | address | address                  |
| epoch | uint256 | withdrawal request epoch |

**Return Values**

| Name | Type    | Description     |
| ---- | ------- | --------------- |
| \[0] | uint256 | received assets |

#### \_epochSharesToAssets

```solidity
function _epochSharesToAssets(address user, uint256 epoch) internal view returns (uint256)
```

Convert epoch shares to assets

**Parameters**

| Name  | Type    | Description              |
| ----- | ------- | ------------------------ |
| user  | address | User address             |
| epoch | uint256 | withdrawal request epoch |

**Return Values**

| Name | Type    | Description      |
| ---- | ------- | ---------------- |
| \[0] | uint256 | converted assets |

#### canWithdraw

```solidity
function canWithdraw(uint256 epoch) public view returns (bool)
```

Check if an epoch is completed or not

**Parameters**

| Name  | Type    | Description  |
| ----- | ------- | ------------ |
| epoch | uint256 | Epoch number |

**Return Values**

| Name | Type | Description                |
| ---- | ---- | -------------------------- |
| \[0] | bool | True if epoch is completed |

#### withdrawableAssets

```solidity
function withdrawableAssets(address user, uint256 epoch) public view returns (uint256)
```

Get withdrawable assets of a user

**Parameters**

| Name  | Type    | Description     |
| ----- | ------- | --------------- |
| user  | address | User address    |
| epoch | uint256 | The vault epoch |

**Return Values**

| Name | Type    | Description                        |
| ---- | ------- | ---------------------------------- |
| \[0] | uint256 | Amount of assets user will receive |

#### withdrawableShares

```solidity
function withdrawableShares(address user, uint256 epoch) public view returns (uint256)
```

Get withdrawable shares of a user

**Parameters**

| Name  | Type    | Description    |
| ----- | ------- | -------------- |
| user  | address | user address   |
| epoch | uint256 | requests epoch |

**Return Values**

| Name | Type    | Description                  |
| ---- | ------- | ---------------------------- |
| \[0] | uint256 | amount of shares to withdraw |

#### getAssets

```solidity
function getAssets(address user, uint256[] epochs) public view returns (uint256 assets)
```

Get total withdrawable assets of a user for multiple epochs

**Parameters**

| Name   | Type       | Description               |
| ------ | ---------- | ------------------------- |
| user   | address    | User address              |
| epochs | uint256\[] | withdrawal request epochs |

**Return Values**

| Name   | Type    | Description               |
| ------ | ------- | ------------------------- |
| assets | uint256 | total withdrawable assets |

#### sweep

```solidity
function sweep(address _asset) external
```

sweep the assets to governance

*only use case in case of emergency*

**Parameters**

| Name    | Type    | Description   |
| ------- | ------- | ------------- |
| \_asset | address | Asset address |


# Security Roadmap

At Affine, the security of user funds is our highest priority. With Affine Restaking protocol, we are putting the highest effort into security to ensure the best practices for the restaking protocol and ultraETH.

### Internal Audit \[Continuous]

**Code Reviews:** Every pull request is reviewed by 2 engineers.&#x20;

**Internal Review Process:** Comprehensive scopes & playbooks, major team-wide reviews, and formal audits by our devs and CTO.&#x20;

**Test Coverage:** Achieving \~100% statement and functionality coverage on Testnet, and ≥ 80% branch coverage by audit contests. \[Currently at 97% and 90% respectively]&#x20;

### **External Audit Roadmap**&#x20;

**✅ Phase 1 \[Pre-Testnet]:** External independent security audit and remediation done on May 7th, 2024&#x20;

**✅** *Testnet was Launched on May 24, 2024*&#x20;

**✅ Phase 2\[Testnet]**: Earn-to-Test Program is live! [Join Discord](https://discord.com/invite/RvSFFfUdvX) to participate.  &#x20;

**✅** *Mainnet Launch \[Launched on June 28, 2024]*&#x20;

**✅** **Phase 3 \[Mainnet]:** Security Audit code with a tier 1 firm \[Completed by Quantstapmp]&#x20;

*⭐️* **Phase 4 \[1000+ ETH TVL] :** Audit Contest + 2nd major tier 1 audit + bug bounty + AI monitoring

<figure><img src="/files/LL2chYK5GEdFF8gZDlHC" alt=""><figcaption><p>Affine Restaking Security Roadmap</p></figcaption></figure>


# Audit Reports

### Phase 4 Audit Report by Certik

The Audit is being conducted by Certik --initial report shows no major issues

{% file src="/files/e33vHhamew5Y1DLhDDtA" %}
Certik Phase 4 Audit
{% endfile %}

### Phase 3 Audit Report by Quantstamp

This audit was completed on June 24, 2024 by[ Quantstamp](http://quantstamp.com/). Check the report here-

{% file src="/files/1jTtBvTlhQMwovN743cz" %}
Quantstamp Phase 3 Audit
{% endfile %}

### Phase 1 Audit Report

The preliminary audit of ultraETH smart contracts has been completed by MaslarovK on May 7, 2024. Check the report -

{% file src="/files/xJTzD2v3dvhgRcRdpi14" %}
MaslarovK Phase 1 Audit
{% endfile %}


# Ecosystem Partners

1. Eigenlayer
2. Symbiotic


# AVS Partners


# Operator Partners


# DeFi Partners


# Gov Token

\[Coming Soon]


# What is Restaking?

The crypto-economic security provided by staked tokens is extended to apps on that network. On-chain applications don't need to bootstrap their security because they inherit it from the underlying chain.

\
However, off-chain applications like oracles and bridges don't inherit crypto-economic security. They have to bootstrap their security, which is expensive and time-consuming (launch a token, incentivize validators, attract retail investors, etc.), and often times, that security they bootstrapped is no comparison to the security of more high-profile off-chain competitors.

Restaking, as facilitated by EigenLayer and Symbiotic, extends the concept of Proof-of-Stake. By empowering users to restake assets to secure numerous additional AVS. Assets restaked to an AVS serve as collateral for its validation process, are subject to slashing, and yield additional rewards, akin to native staking. These restaked tokens become locked within the mother protocol (EigenLayer or Symbiotic).

### **Why is it called restaking?**&#x20;

It's called "restaking" because you're taking your **existing** staked tokens (staked to their native network) and staking them a second time to secure AVSs. Basically, you're staking twice. Of course, this increases your risk since your tokens can be slashed by two different entities (the native network and the restaking network), but it also increases your yield.

### What is a Liquid Restaking Token?

Liquid Restaking Tokens represent assets that have undergone restaking on EigenLayer to safeguard AVSs. These tokens, akin to Liquid Staking Tokens (LSTs), can actively participate in decentralized finance (DeFi) markets.


# EigenLayer

### **1. What is EigenLayer**&#x20;

EigenLayer is a protocol operating on Ethereum, introducing a novel concept called "restaking" as a cryptoeconomic primitive. Unlike conventional staking pools, restaking enables the reuse of assets to secure multiple Actively Validated Services (AVS) with the same initial capital. Moreover, EigenLayer is uniquely designed to allow Ethereum (ETH) already staked and engaged in Ethereum consensus to be repurposed for securing additional services.

### 2. Restakers

These are the individuals or entities who have staked ETH, either directly or through liquid staking derivatives. Restakers have the option to restake their ETH via Eigenlayer to provide additional security to services, earning rewards and points in exchange.

### 3. Node Operators

These participants play a pivotal role by choosing which AVSs to support and actively validate. In return for their service, node operators earn yields from the supported AVSs. Crucially, node operators face the risk of slashing (loss of staked ETH) due to misbehavior or failure of validation duties.

### 4. Actively Validated Services (AVS)

These are applications including, but not limited to, rollups, data availability layers, oracles, or other specialized services that require security guarantees via consensus. By opting into Eigenlayer, AVSs access Ethereum’s pool of staked ETH.

### 5. Liquid Restaking Tokens (LRTs)

While not directly a part of the Eigenlayer, LRTs streamline the process for users to participate in the Eigenlayer. They function as staking pools for restaking. By depositing ETH into LRTs (for example, ezETH \[3], pufETH \[1], etc.), users receive representative tokens. These tokens represent a share in a node operator network and earn Eigenlayer points, with potential additional rewards offered by the LRT providers themselves.

<br>

<br>


# EigenLayer Points

Eigenpoints, or restaking points, quantifies an individual's contribution to the shared security of the EigenLayer ecosystem. It represents staking participation measured by the integrated amount staked over time, denominated in ETH-hours.

#### EigenLayer Points Calculation

ultraETH restakers will earn 1 Eigenlayer point eery hour for each stETH deposit.&#x20;

For instance, a user who stakes 1 stETH for 10 days should accrue 240 restaking points over this time period (1 ETH × × 10 days × × 24 hours/day = 240 ETH ⋅ ⋅ hours).

#### How to check my EigenLayer points

Your stETH deposits are socialized with other restakers and restaked with P2P on EigenLayer. Therefore, individual EigenLayer Pt wallet balances cannot be viewed on the EigenLayer Dapp. However, you can always check your EigenLayer points on Affine Restaking dApp.&#x20;


# Symbiotic

Symbiotic is a permissionless restaking protocol of enshrined principles that enables protocol participants to flexibly form trust-minimized shared security agreements. Participants of the Symbiotic protocol economy include node operators, decentralized protocols, LRTs/vaults and providers of economic security (restakers).

Symbiotic is a security coordination layer enabling builders to fully control and continuously adapt their own restaking implementation in a permissionless manner to service any possible decentralized infrastructure use case and its requirements. This enables the Symbiotic protocol to help scale decentralized networks safely, transparently, and in a capital-efficient way.

### Components of Symbiotic Protocol

<figure><img src="/files/Beu3ddtlyLBDWR6mmeBz" alt="" width="375"><figcaption></figcaption></figure>

**Collateral** (aka stake, commitments,…)

> The security layer of Symbiotic. Collateral is an abstraction used to represent underlying onchain assets, which are chain- and asset-agnostic in Symbiotic. Collateral in Symbiotic can encompass ERC20 tokens, withdrawal credentials of Ethereum validators, or other onchain assets such as LP positions, without limitations regarding which blockchains the positions are held on.

**Vaults** (aka operator staking pools, liquid (re)staking protocols,…)

> The (re)staking layer of Symbiotic. Delegation of collateral to operators across networks is handled by vaults that can be curated in a custom manner (e.g. by liquid (re)staking providers such as Lido or institutional holders) or through delegations to operator-specific vaults.

**Operators** (aka validators, sequencers, guardians, keepers,…)

> Operators in Symbiotic are defined as entities running infrastructure for networks. In Proof-of-Stake, successful staking providers have established a brand identity and operate across networks. The Symbiotic protocol creates a registry of operators storing information about their history and enabling them to opt-in to networks and receive economic backing from restakers through vaults.

**Resolvers** (aka slashing committees, proving mechanisms, dispute resolution frameworks,…)

> Resolvers are entities or contracts that are tasked to pass or veto slashing penalties incurred by operators on networks they are providing services to. They are agreed upon by vaults - representing providers of economic security - and the networks they provide security for.

**Networks** (aka appchains, rollups, AVSs,…)

> Networks in Symbiotic are defined as protocols that require a distributed set of node operators to provide trust-minimized services, such as - among others - decentralized sequencing of transactions, coming to consensus about offchain data and bringing it onchain (oracles), automating specific protocol functions (keepers), etc.

**Source:** [Symbiotic Documentation](https://docs.symbiotic.fi/)


