# Meet Morpheus

## Morpheus Is Freedom and Liberty For All

### The following 10 values embody the type of communities, projects and freedom tech Morpheus is built to protect:

### <mark style="color:blue;">1. Open Source</mark>

Code must be freely reviewable, editable, and forkable. No closed boxes. Ever.

### <mark style="color:blue;">2. Peer to Peer</mark>

Direct connections between people — no centralized intermediaries calling the shots.

### <mark style="color:blue;">3. Public Blockchain</mark>

A distributed, immutable record of truth. Anyone can verify the system follows its own rules.

### <mark style="color:blue;">4. Tokenized Ownership</mark>

Power and participation for everyone. Not a company — a community-owned network.

### <mark style="color:blue;">5. Permissionless</mark>

No one should ever have to ask permission to build or use Morpheus.

### <mark style="color:blue;">6. Freedom of Access</mark>

No blacklists. No censorship. If you can reach the chain, you’re free to use it.

### <mark style="color:blue;">7. Privacy Preserving</mark>

No one should be forced to expose their identity or data. Privacy is a right.

### <mark style="color:blue;">8. Freedom of Choice / Exit</mark>

No lock-ins. Leave, fork or evolve — the system will never trap you.

### <mark style="color:blue;">9. Self Sovereign Identity</mark>

Users generate their own identities and choose when to share them.

### <mark style="color:blue;">10. Freedom of Association</mark>

Coordinate. Organize. Build movements. On your terms.

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


# What is Morpheus?

{% hint style="info" %} <mark style="color:purple;">**This Gitbook is authored by the Morpheus Open Source Contributors Community.**</mark> \ <mark style="color:purple;">**All the ideas and concepts presented here are the result of collaborative efforts of individuals passionate about decentralized technologies and AI.**</mark>
{% endhint %}

Morpheus is the decentralized infrastructure layer where anyone can **build**, **deploy**, and **scale** AI without gatekeepers.

It combines yield-powered tokenomics, decentralized compute, and open-source code into a permissionless network — with the native token [**MOR**](/tokenomics/mor-emissions) aligning incentives through daily emissions to four contributor groups: Capital, Compute, Code, and Builders.

### What Makes Morpheus Different

❌ **No formal team, founders, or registered entity** – the network is not controlled by a company or foundation.

🌍 **Globally distributed contributors** – a community dedicated to decentralized AI and open-source development.

💸 **No token sale, no pre-mine, no VC allocations** – MOR was not issued through private deals or insider advantages.

⚡ **Fair Launch** – equal conditions and opportunities for everyone from day one.

### Origins

On **September 2, 2023**, a group of anonymous authors — identifying themselves as *Morpheus, Trinity, and Neo* — published [**a groundbreaking paper**](https://mor.org/whitepaper), marking the inception of the Morpheus network.

Since then, Morpheus has followed a uniquely free-market path. Its economic design draws on principles of **individual sovereignty, voluntary markets, and anarcho-capitalism** — making it one of the first networks since Bitcoin to fully embrace a permissionless, market-driven model.

### Today

Morpheus has grown from a whitepaper into a working network where contributors stake, compute, build, and code — **expanding freedom through decentralized AI**.

Thanks to all those in the community **Staking, Computing, Building & Coding for Freedom.**


# Morpheus Eras

The Morpheus launch is structured in sequential **Eras**, inspired by Ethereum’s **Genesis** → **Frontier** → **Homestead** → **Metropolis** → **Serenity** sequence. Each era represents a distinct stage of growth, unlocking new capabilities and broadening participation.

<figure><img src="/files/HlRg6oM4kDmrPm6u9tAm" alt=""><figcaption><p>Morpheus Launch Phases</p></figcaption></figure>

### <mark style="color:blue;">Genesis Era</mark> <mark style="color:blue;"></mark>*<mark style="color:blue;">(Sep 2, 2023 → Feb 8, 2024)</mark>*

✅ **Milestones:** Whitepaper published; first local Smart Agents install (Oct 2023).\
✅ **Preparations:** Audits, testnet deployments.\
✅ **Launch:** Smart contracts for the MOR token and Fair Launch deployed on Ethereum and Arbitrum

{% hint style="success" %}
February 8th 2024 is the 28th Anniversary of ["A Declaration of the Independence of Cyberspace"](https://www.eff.org/cyberspace-independence)
{% endhint %}

### <mark style="color:blue;">Frontier Era</mark> <mark style="color:blue;"></mark>*<mark style="color:blue;">(Feb 9, 2024 → May 8, 2024)</mark>*

✅ **Fair Launch begins.** MOR emissions start from Day 1, allocated to Capital, Compute, Code, Builders and Protection Fund.\
✅ **Liquidity Bootstrapping:** 90-day period to establish DEX pools and liquidity.\
✅ **Claim & Transfer:** After 90 days (May 8, 2024), MOR becomes claimable and transferable.

### <mark style="color:blue;">Homestead Era</mark> <mark style="color:blue;"></mark>*<mark style="color:blue;">(May 9, 2024 → Nov 18, 2024)</mark>*

✅ Compute infrastructure goes live: Morpheus-Lumerin Compute Node and Proxy Router launch.\
✅ **Decentralized inference available for market.**\
✅ MOR rewards extended to Compute Providers.

### <mark style="color:blue;">Metropolis Era</mark> <mark style="color:blue;"></mark>*<mark style="color:blue;">(Nov 18, 2024 → Q1 2025)</mark>*

✅ **Smart Agents evolved to** [**MySuperAgent.**](/meet-morpheus/mysuperagent)\
✅ **Launch of community MOR stake guided** [**Builder**](https://gitbook.mor.org/builders/) **rewards.**\
✅ Further feature unlocks as protocol utility broadens.

### <mark style="color:blue;">Serenity Era</mark> <mark style="color:blue;"></mark>*<mark style="color:blue;">(Q1 2025 → Q3 2025)</mark>*

✅ **Morpheus** [**API Gateway**](/morpheus-inference-marketplace/api-gateway) **launch**, enabling developers and users to access decentralized inference seamlessly.\
✅ Ecosystem expansion: **multi-chain deployments** and **additional yield types.**\
✅ Protocol matures with diversified liquidity.\
✅ Foundation for mass adoption established.

### <mark style="color:blue;">Zion Era</mark> <mark style="color:blue;"></mark>*<mark style="color:blue;">(Q3 2025 → 2026 and beyond)</mark>* <mark style="color:purple;">**← You are here**</mark>

🔄 **Scaling for End Users:** Focus shifts from protocol bootstrapping to large-scale adoption.\
🔄 **Agent Economy:** Applications and agents reach mainstream usage across industries.\
🔄 **Global Inference Marketplace:** Expanded infrastructure to serve billions of inference requests.\
🔄 **Sustainable Growth:** Continuous MOR emissions align incentives while supporting long-term network sustainability.

The **Zion Era** represents the vision of Morpheus fully realized — a decentralized AI infrastructure at scale, open to everyone.

⚡ *Each era builds on the last, moving from whitepaper to global adoption, with MOR emissions fueling the journey.*


# Morpheus Contributors

The Morpheus is structured around four critical categories of contributors incentivized with [MOR token emissions.](/tokenomics/mor-emissions) This design is essential to ensuring the accessibility, decentralization and robust development.

By recognizing and rewarding **Capital Providers, Compute Providers, Code Providers, and Application Builders** efforts Morpheus creates a sustainable, decentralized environment that echoes the success of earlier blockchain projects like Bitcoin and Ethereum, where open competition for scarce digital tokens fostered long-term infrastructure development.

{% tabs %}
{% tab title="Capital Providers" %}
Are integral to the [Techno Capital Machine](/tokenomics/techno-capital-machine), offering yield-bearing capital that drives [Morpheus\` Protocol-Owned Liquidity](/tokenomics/protocol-owned-liquidity-pol). Their participation ensures that the network has the financial resources necessary to grow and sustain itself. They receive MOR tokens prorated to their yield-bearing capital contribution against the total deposited pool.
{% endtab %}

{% tab title="Compute Providers" %}
Offer the primary compute resources required for AI inference, a vital function for the network. Their decentralized contribution of compute, storage, and bandwidth ensures that the Morpheus network remains scalable and resilient. The Morpheus network pays compute providers only for compute actually provided through a competitive bid process.
{% endtab %}

{% tab title="Code Providers" %}
Are responsible for the ongoing development, upgrades, and innovation within the Morpheus codebase. By contributing to the evolution of the software they request "weights" – units of work that determine their share of MOR emissions, ensuring that contributions are fairly compensated.
{% endtab %}

{% tab title="App Builders" %}
Are the creative force driving the adoption of Morpheus through the development of frontends, end-user applications, valuable smart agents, dashboards, tools, and other resources that serve the community’s needs. Their rewards are tied to user engagement, as users can stake their MOR tokens to support specific projects, creating a market-driven incentive for high-quality development.
{% endtab %}
{% endtabs %}

### Free market approach

Contributors operate in a competitive free market for providing the most value:

* **Capital Providers** compete to provide liquidity
* **Compute Providers** compete to supply compute power
* **Code Providers** compete to enhance the Morpheus open-source software
* **Builders** compete to deliver valuable smart agents, applications and solutions.

This decentralized, competitive environment ensures that Morpheus remains dynamic, innovative, and truly reflective of the community's needs.


# Key Use Cases

Morpheus is a chain-agnostic decentralized platform designed to support a wide range of decentralized AI applications, much like how Ethereum enables Smart Contracts. At the core of Morpheus are DeAI applications such as Smart Agents, general-purpose AI that translates human intent into Web3 actions to bring Web3 to the masses. However, Smart Agents are just one facet of Morpheus’s potential.

### Key Use Cases

* &#x20;**Decentralized AI Services**\
  Morpheus enables developers to deploy AI models on a decentralized network, reducing reliance on traditional cloud providers and fostering open access to AI resources.
* &#x20;**Decentralized Compute Aggregator**\
  By aggregating compute power from both centralized and decentralized sources, Morpheus offers competitive rates, providing users with affordable compute resources on demand.
* **Decentralized Agents Marketplace**\
  A marketplace for AI-driven Smart Agents, where users can deploy and utilize agents for tasks across fields, enhancing automation and efficiency.
* **DeFi and Staking Mechanisms**\
  MOR tokens offer various staking mechanisms that expand their utility within DeFi, similar to ETH in the Ethereum ecosystem.
* **Fair Launch for Projects**\
  Projects launched on Morpheus benefit from proven [Fair Launch contracts](/tokenomics/techno-capital-machine/mor-20-fair-launch-standard) and community support, accessing capital, code, and resources that lower entry barriers for developers.
* **Enhanced Privacy**\
  With decentralized data handling, Morpheus safeguards user privacy by default, making it an ideal fit for privacy-sensitive and autonomous applications.\
  \
  If you're interested in implementing one of these use cases or have your own idea but need additional support, join community discussion on [Discord](https://discord.gg/morpheusai).


# Atomic Governance

Morpheus is unique in many aspects and governance is no exception. Morpheus is unique in many ways, and governance is no exception. To maintain an unprecedented pace of development and streamline decision-making related to software, infrastructure, capital, compute, and frontends, Morpheus has adopted the **Atomic Governance** model. This model allows every individual involved to freely associate and make independent decisions about their contributions, without the need for votes or friction being introduced.&#x20;

For example, at the community level, Morpheus repository maintainers can decide whether or not to merge open-source contributions from Coders, based on the value of the contribution and the reward the contributor expects. Compute providers choose which AI models they want to support and at what price. Meanwhile, MOR holders decide which projects to back by staking MOR, directing rewards to Builders based on their interest in the software being developed.\
\
At the protocol level, **Atomic Governance** diverges from typical Web3 governance models like DAOs. Here’s how it works:

1. Proposals are made by the community, followed by general discussion.
2. Repository owners identify individuals with the relevant expertise and involve them in the technical design and planning process.
3. Once the best technical design is identified and developers confirm they can implement and test it within a reasonable timeframe, work begins.
4. The broader coding community is welcome to contribute by submitting issues, pull requests, and other contributions.
5. No broad voting on the proposal, design, or code is required. Decisions are based on expert consensus, with the final judgment made by the repository owner.
6. After the code is developed and deployed every user maintains the right to use or not use it. To fork the code and otherwise create a different version or opt out of the project.

This approach to governance is aligned with a [free-market ethos](/), allowing for rapid development without the delays and complexities of trying to build consensus among large groups. It’s especially advantageous where quick iterations and adjustments are crucial to achieving product-market fit and adapting to evolving market conditions.


# MySuperAgent

### Introducing MySuperAgent: Your Crypto Companion Agents

In the rapidly evolving cryptocurrency landscape, MySuperAgent provides users with advanced AI-driven tools designed to simplify complex tasks. Specifically tailored for crypto traders, investors, and enthusiasts, MySuperAgent streamlines the crypto experience, enabling users to confidently and effectively navigate the market.

### Specialized Agents for Crypto Users

MySuperAgent offers a suite of specialized agents focused on critical tasks such as token analysis, market insights, and sentiment tracking. These agents work together seamlessly, providing comprehensive support for various crypto strategies—from monitoring Bitcoin market trends to evaluating the security of Solana tokens.

Key features include:

* **Token Analysis:** Detailed views and insights into the most-viewed tokens via Rugcheck.
* **Market Insights:** Understanding how recent news events impact cryptocurrencies.
* **Real-time Metrics:** Comprehensive statistics on market capitalization, liquidity, trading volumes, and price movements via Codex.

<figure><img src="/files/eBnrliwUengto0kvYYTB" alt="" width="563"><figcaption></figcaption></figure>

These tools equip users with the necessary information to make well-informed and timely decisions in a dynamic market.

### Pre-Built API Integrations for Enhanced Functionality

MySuperAgent’s capabilities are further enhanced through strategic API integrations:

* **Coinbase Base Agent:** Automate DeFi protocol interactions and token swaps efficiently via 1inch, securing optimal exchange rates.
* **Social Media Management:** Efficiently manage social presence through integrated tweet crafting and publishing.
* **Sentiment Analysis (Elfa):** Gain real-time insights from social media platforms such as Twitter and Reddit to monitor market sentiment.
* **Comprehensive Crypto Metrics (Codex):** Access vital crypto metrics, including detailed on-chain analytics.

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

### Expanding with Community and Third-Party Agents

MySuperAgent continues to expand by enabling integrations with external platforms and inviting third-party agents into its ecosystem. This collaborative environment enhances versatility, continually enriching the suite of available AI-driven services and resources.

### Conclusion

MySuperAgent provides efficient, secure, and AI-powered tools designed to support informed decision-making in cryptocurrency trading.&#x20;

Learn more by visiting [MySuperAgent.io](https://mysuperagent.io).


# Difference Between an LLM and an AI Agent

In AI, Large Language Models (LLMs) generate responses based on input but are limited to single tasks. In contrast, AI agents operate more dynamically, combining specialized roles to make complex decisions and adapt to varied challenges. This difference enables agents to manage tasks, delegate responsibilities, and collaborate effectively with other agents and humans.

Agents can be composed to perform complex tasks, with each agent fulfilling a specific role.

For example, in a development team, different roles like project manager, product manager, backend engineer, frontend engineer, DevOps specialist, and scrum master work together to achieve shared goals. Similarly, in an AI ecosystem, agents can be organized to manage and direct other agents to complete tasks. For instance, the MORagents system has a basic implementation where a delegator agent assigns your query to specific task agents (such as live news, MOR rewards, Tweet generator, etc.).

In contrast, a pure Large Language Model (LLM) is more limited in function. It simply generates text in response to an input query, similar to how a worker uses a tool to complete a task. An agent, however, is capable of using an LLM to make decisions—such as choosing whether to use the LLM again, switching to a different tool, or taking an entirely new approach to accomplish a task.

The primary advantage of agents is that they enable a computer, rather than a person, to make complex decisions autonomously, collaborating with other agents and even humans as needed.

Another view on Agents is given by Lumerin Protocol below

{% embed url="<https://x.com/HelloLumerin/status/1851571555119120630>" %}


# 10 Reasons to be Excited About Morpheus

**by Jeff McDonald, Morpheus contributor**

> “Compute is going to be the currency of the future, maybe the most precious commodity in the world.” — Sam Altman.

## For the Investors

#### 1. The Techno Capital Machine

It is more than just a quirky name; it's a [fundraising game-changer](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Capital%20Providers%2C%20MOR20%2C%20TCM/Techno%20Capital%20Machine%20\(TCM\).md#tcm-smart-contracts-for-fair-launch). Investors start earning MOR daily by depositing ETH as stETH into the Morpheus contract on Ethereum's main chain. The best part? Users can withdraw their stETH anytime and claim their earned MOR: your keys, your coins. Over 1,5% of LIDO's stETH were in the Morpheus contract at some moment.

#### 2. Ever-growing Liquidity

Unlike traditional liquidity providers, who can withdraw their funds to support a coin's liquidity at any time, in Morpheus, stETH yields from capital providers are directed to Uniswap's liquidity pool to create[Protocol-Owned Liquidity (PoL)](/tokenomics/protocol-owned-liquidity-pol), which only increases daily. This growth is a key metric for whale investors.

#### 3. Real Life Utility for MOR

Holders can access [free AI compute daily](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Compute%20Providers/Yellowstone%20Compute%20Model.md#accessrate) based on their token ownership percentage. This means owning MOR grants direct access to the network's computing power without recurring fees.

#### 4. And Also Staking MOR

Instead of navigating complex quadratic voting processes, DAOs, or politically swayed community funds, MOR holders vote directly by [staking their tokens](https://github.com/MorpheusAIs/MRC/blob/main/PENDING/MRC41.md) with new projects they support and receiving rewards for their efforts.

## For the Devs

#### 5. Ample Funds to Pay the Builders on Day One

[Contributors providing computing power or models](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Code%20Providers/Morpheus%20Builders%20Guide.md) are compensated immediately upon launch, eliminating the need for a lengthy marketing grind and user acquisition. The stETH depositors have already bootstrapped the ecosystem.

#### 6. The Morpheus App Store for AI

Morpheus acts as a marketplace for compute providers and AI code. Built on principles of free market competition and decentralization, it rewards contributors directly without intermediaries or centralized control. With a free market approach, the best models and compute providers acquire the most consumers.

#### 7. Scales Like an Ecosystem, but Runs Like Contract

Morpheus's [decentralized contracts govern](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Compute%20Providers/Morpheus%20Lumerin%20Model.md#ecosystem-model) and control [ecosystem funds](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Capital%20Providers%2C%20MOR20%2C%20TCM/The%20Morpheus%20Asset%20Integration%20Framework.md) efficiently with minimal overhead. While not as complex as L1 or L2 solutions to build from scratch and maintain, its marketplace model enables exponential scalability. Only recently has blockchain development technology matured to the point where this kind of project is possible.

## For the Entrepreneurs

#### 8. Application Building Rewards

Morpheus incentivizes those who further the adoption of Morpheus. Referrers who help others deposit stETH also receive rewards, decentralizing community leadership and fostering a global network of contributors while helping to increase funds for operations.

#### 9. Critical Real World Need and Market Fit

Decentralized AI addresses urgent privacy concerns and mistrust in big tech. Morpheus leverages blockchain advancements to deploy AI on a decentralized network, providing an uncensored and privacy-centric alternative to centralized platforms.

#### 10. MOR20 Standard

Morpheus is a set of contracts that include the fundraising mechanism (The Techno Capital Machine) used to help bootstrap an AI marketplace. These contracts are open-sourced and now battle-tested in a real-world environment, securing over $500,000,000 USD worth of stETH. They are being packaged today as part of the [MOR20 standard](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Capital%20Providers%2C%20MOR20%2C%20TCM/Techno%20Capital%20Machine%20\(TCM\).md#automated-recurring-revenue--rewards-arr-generalizing-the-tcm-model---mor20-token-standard), which allows others to use this model to help fund their projects.

***

**Jeff's Contacts**

* Telegram: @jabo38
* Twitter: @thejabo38


# Tokenomics

Morpheus' tokenomic is designed to create a closed economic cycle that incentivizes and rewards all contributors crucial to the decentralized AI ecosystem. This structure ensures the sustained development, deployment, and operation of decentralized AI applications within Morpheus platform, fostering a balanced and self-sustaining ecosystem where all participants — be it capital providers, compute providers, coders, or builders — are fairly compensated in native token called MOR.

## MOR Token

The MOR Token Supply is limited to a **maximum of 42,000,000 tokens** that will ever exist. The distribution started on February 8th 2024 with all four groups of contributors earning the tokens by providing forms of proof of work (labor) and proof of stake (capital) to the network ensuring that every MOR issued is backed by value brough to the protocol.

No pre-mine. No early token sale. Just a fair launch.

<figure><img src="/files/l7gyIL1dZhVHV6lC0Rzw" alt=""><figcaption><p>MOR token distribution</p></figcaption></figure>

Each group is allocated equal shares (24% each) of MOR token emissions with 4% set aside for [Protection Fund.](/security-audits/protection-fund) This equal distribution recognizes the interdependence of these groups, ensuring that each is adequately motivated to contribute to the ecosystem’s growth. Equal shares foster collaboration, as no single group holds disproportionate influence, promoting a balanced and decentralized network.

This structure drives a global community of contributors and builders to collaborate on an ever-expanding scale. As AI Agents increasingly dominate economic activity, Morpheus will stand at the forefront, serving as the driving force behind the evolution of Free AI. This relentless momentum ensures that Morpheus remains central to the future of decentralized AI, empowering innovation and growth across the ecosystem.


# MOR Utility

At the core of the Morpheus token economy is MOR, a fair-launched utility token that powers the network, facilitating value movement and free-market dynamics among end users, builders, smart agents, DeAi applications, compute providers, consumers, developers, and capital providers.

The utilities of the MOR token include:

* rewarding ecosystem contributors;
* the primary means of payment for ecosystem AI applications;
* providing access to services within the ecosystem;
* [Protocol-Owned Liquidity](/tokenomics/protocol-owned-liquidity-pol) asset;
* allowing MOR holders to stake tokens for a free daily compute quota, accessing the network’s entire compute capacity;
* a staking asset for Compute Providers competing for user inference requests;
* incentivizing participants in the capital providers’ [referral program](/tokenomics/referral-program);
* a base asset for projects launched with the [MOR-20 standard](/tokenomics/techno-capital-machine/mor-20-fair-launch-standard);
* a tool to allocate rewards to builders through staking;
* [locking MOR](/tokenomics/mor-emissions#tail-emissions) to ensure rewards distribution in future Epochs;
* a multichain asset that allows Morpheus to remain chain-agnostic, supporting interoperability across blockchain networks.

This list represents the foundational utility set of MOR, which continues expanding as the Morpheus ecosystem grows, bringing new functionalities and opportunities for MOR holders.


# MOR Emissions

Morpheus rewards have started at 14,400 MOR per day on February 8th 2024 and decline by 2.468994701 MOR each day until the reward reaches 0 on day 5,833 or January 28th, 2040.

<figure><img src="/files/pPjqkJedo7bobYA9JAhR" alt=""><figcaption><p>MOR Emissions for Epoch 1</p></figcaption></figure>

Daily emissions distributed between buckets in proportions:

* 3,456 MOR (24%) tokens for Compute Providers;
* 3,456 MOR (24%) tokens for Code Contributors;
* 3,456 MOR (24%) tokens for Capital Providers;
* 3,456 MOR (24%) tokens for Application Builders.

With the remainder of 576 MOR (4%) set aside for [Protection Fund](/security-audits/protection-fund).

<table data-full-width="true"><thead><tr><th width="168">Schedule</th><th width="207">MOR Emitted</th><th width="188">% Decrease</th><th>Change</th></tr></thead><tbody><tr><td>Year 1</td><td>5,091,985</td><td>N/A</td><td>N/A</td></tr><tr><td>Year 2</td><td>9,855,038</td><td>-48.37%</td><td>4,763,05</td></tr><tr><td>Year 3</td><td>14,289,159</td><td>-31.00%</td><td>4,434,12</td></tr><tr><td>Year 4</td><td>18,394,348</td><td>-22.34%</td><td>4,105,18</td></tr><tr><td>Year 5</td><td>22,170,605</td><td>-17.04%</td><td>3,776,25</td></tr><tr><td>Year 6</td><td>25,617,931</td><td>-13.48%</td><td>3,447,32</td></tr><tr><td>Year 7</td><td>28,736,325</td><td>-10.85%</td><td>3,118,39</td></tr><tr><td>Year 8</td><td>31,525,787</td><td>-8.82%</td><td>2,789,46</td></tr><tr><td>Year 9</td><td>33,986,317</td><td>-7.22%</td><td>2,460,53</td></tr><tr><td>Year 10</td><td>36,117,915</td><td>-6.28%</td><td>2,131,59</td></tr><tr><td>Year 11</td><td>37,920,581</td><td>-4.76%</td><td>1,802,66</td></tr><tr><td>Year 12</td><td>39,394,316</td><td>-3.88%</td><td>1,473,73</td></tr><tr><td>Year 13</td><td>40,539,119</td><td>-2.91%</td><td>1,144,80</td></tr><tr><td>Year 14</td><td>41,354,990</td><td>-2.02%</td><td>815,87</td></tr><tr><td>Year 15</td><td>41,841,929</td><td>-1.18%</td><td>486,93</td></tr><tr><td>Year 16</td><td>42,000,000</td><td>-0.38%</td><td>158,07</td></tr></tbody></table>

## Tail Emissions

Since Bitcoin's launch, the question, "What will happen when the block rewards finally stop?" has sparked ongoing debate. To sidestep this issue in the context of Morpheus and to ensure long-term alignment among coders, builders, compute providers, and capital providers, Morpheus introduced **"Epochs"** and **"Tail Emissions"** of MOR tokens.

MOR tail emissions will begin after the final MOR tokens are emitted on day 5,833 of the distribution schedule, which marks the end of the 16-year **Epoch 1**.

The tail emission amount will be calculated as 50% of the MOR tokens set aside for **Epoch 2** over the previous 16 years. This tail emission value will then be distributed over the next 5,833 days.

For example, here is the table that represents Tail Emissions schedule if 10% of MOR supply will be locked for this purpose each epoch.

<figure><img src="/files/XcOjZdhOgZ5u3vqiqBDF" alt=""><figcaption><p>MOR Tail Emissions schedule</p></figcaption></figure>

This process will continue indefinitely, ensuring that future coders, compute providers, builders, and capital contributors are always guaranteed rewards, while MOR tokens become increasingly scarce with each Epoch.

<figure><img src="/files/2HSK8gKJ3dbmpymabOxc" alt=""><figcaption><p>MOR Supply Decrease with Tail Emissions</p></figcaption></figure>


# Techno Capital Machine

The term Techno Capital Machine is inspired by renowned philosopher [Beff Jezos](https://twitter.com/BasedBeffJezos) and has been first implemented by the Morpheus community to revolutionize how developers are rewarded for their software. The model well validated during the Morpheus Fair Launch, with over $200 Million USD of stETH (Lido Staked Ethereum) Contributed in the first 10 days and over $500 million in the following months.

The Morpheus community is leveraging this framework to accelerate open source development of the protocol.&#x20;

<mark style="color:blue;">**The Techno Capital Machine is tokenomics engine that allows developers to fund development and start off open source decentralized projects as Fair Launch.**</mark> \
\
More specifically, users deposit yield bearing assets directly into smart contract that utilizes generated yield for creation of Protocol-Owned Liquidity and reward capital providers with native tokens of a project pro rate to their shares in the total deposited pool.&#x20;

This design simplifies the creation of native tokens, ensures consistent demand for them, and strengthens the essential ecosystem liquidity. It makes it easier for all users to buy or sell native tokens at scale, supporting long-term project development through Protocol-Owned Liquidity and a fair price discovery mechanism.

#### Benefits of the Techno Capital Machine include:

1. Easy to create a fair launch native token to power an open source project.
2. Permissionless as its jurisdiction agnostic, no company needed.
3. The user maintains custody of their principle in the yield producing asset.
4. The yield contributed daily creates a sustainable demand for the native token.
5. The yield contributed daily grows the liquidity of the AMM over time.
6. Holders of the native token can add additional functionality to their Smart Agent.
7. Creators of the native token can get liquidity for the token they earn.


# Capital Contract

The **Capital Contract** is the core component of the Techno-Capital Machine. It manages user deposits, directs yield, and distributes MOR rewards.

### Evolution

#### V1 *(Launched Feb 8, 2024)*

* Single-asset deposits limited to **stETH**
* Yield sourced from **Lido stETH staking**
* Depositors earned MOR emissions based on deposit size and **Power Factor multiplier**
* Withdrawals possible after 7 days (no permanent lockups)
* Fully **non-custodial design** from the start — users always retained control over deposits
* **Audited contracts** deployed for the Fair Launch

***

#### V2 *(Launched Sept 18, 2025)*

* **Multi-asset support** – stETH, USDC, USDT, wBTC (with more to be added)
* **Expanded yield strategies** – new assets routed through **Aave** and other protocols (not just Lido)
* **Referral system introduced** – depositors can share and earn bonuses for bringing new capital
* **Enhanced security** – Zenith audit, Code4Arena competition, and ongoing bug bounty layered on top of V1’s audit baseline

***

### What Stays the Same

* **Non-custodial by design** – deposits always remain user-controlled
* Deposits fuel the **Techno-Capital Machine** → yield is used for MOR buybacks, Protocol-Owned Liquidity, and token burns
* Depositors rewarded with **MOR emissions**
* Withdrawals possible after a minimum 7-day delay

***

### Key Differences at a Glance

| Feature          | V1                                    | V2                                                             |
| ---------------- | ------------------------------------- | -------------------------------------------------------------- |
| Supported Assets | stETH only                            | stETH, USDC, USDT, wBTC, wETH (expandable)                     |
| Yield Source     | Lido                                  | Lido + Aave                                                    |
| Security         | Independent audit + Public Bug Bounty | Independent audit + Public Bug Bounty + Self-hosted Bug Bounty |
| Referral Program | Fully on-chain                        | Fully on-chain, improved                                       |
| Flexibility      | Single-asset deposits                 | Multi-asset, modular yield expansion                           |

### Why V2 Matters

V2 extends the Capital Contract from a **single-asset yield engine** into a **multi-asset, scalable capital layer**. It enables broader participation, diversified yield, and stronger resilience — while preserving the fair-launch ethos and non-custodial design that have been present since day one.

### Technical Documentation

For contract addresses, functions, and integration details, see the full [Distribution Protocol Documentation](/smart-contracts/documentation/distribution-protocol/deployed-contracts).


# MOR 20 Fair Launch Standard

The Morpheus community is deeply committed to the open-source ethos, valuing transparency, collaboration, and shared innovation. In line with these principles, **MOR20**, the generalized version of Morpheus Smart Contracts, has been introduced for free community use.&#x20;

Any project, whether within or beyond the realms of Web3 and AI can leverage MOR20 to kickstart their initiative with ease by creating an Automated Recurring Revenue stream powered by the Techno Capital Machine engine, which is highly attractive to both projects and capital providers.

#### Key benefits of MOR20 include:

* **Effortless Fair Launch:** Simplifies the creation of fair launches for projects.
* **Out-of-the-Box Infrastructure:** Provides ready-to-use infrastructure.
* **Audited and Battle-Tested Contracts:** Ensures security and reliability.
* **Fair Price Discovery:** Offers a fair pricing mechanism and access to the vast network effects of the Morpheus community.
* **Customizable Contracts:** Projects can tailor contracts to fit their specific goals and requirements.
* **Versatile Revenue Model:** The MOR20 model can be extended to various project types, enabling recurring revenue or payments from users via yield-bearing assets.

Projects bootstrapping with MOR20 contribute **0.35% of the generated yield** to Morpheus [Protocol-Owned Liquidity (PoL)](/tokenomics/protocol-owned-liquidity-pol), providing ongoing support to the ecosystem.&#x20;

Recent projects launched using MOR20 contracts include [**AO**](https://ao.arweave.dev/#/mint) **on Arweave** and [**Nounspace**](https://www.nounspace.com/homebase), collectively collected over **150,000 stETH**.

<figure><img src="/files/amCHDHv5oZZBNvKJKsb9" alt=""><figcaption><p>AO Fair Launch Dashboard</p></figcaption></figure>

You can find the full Smart Contract description on [MOR 20 Contracts](/smart-contracts/documentation/mor-20-contracts)page and related security audits on [Security Audits](/security-audits)

{% hint style="success" %}
For a deeper understanding of the concept, read the following documents:

* [MOR20 Value Proposition](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Capital%20Providers%2C%20MOR20%2C%20TCM/MOR20%20Value%20Proposition.md#introduction)
* [Research paper "MOR20 A Standard for Recurring Protocol Payments and Payouts in Web3"](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Capital%20Providers%2C%20MOR20%2C%20TCM/MOR20%20A%20Standard%20for%20Recurring%20Protocol%20Payments%20and%20Payouts%20in%20Web3.pdf)
  {% endhint %}


# Protocol-Owned Liquidity (PoL)

Liquidity is a critical element of any Web3 project, as it underpins the token economy. Deep liquidity promotes market stability, reduces volatility, and builds trust among users. For Morpheus, this is especially vital to handle an ever-growing number of users and ensure fair rewards for contributors.

**Morpheus Protocol-Owned Liquidity** is liquidity owned and controlled by the protocol itself, rather than by individual liquidity providers. This approach ensures transparency, trust, and guarantees the protocol's long-term sustainability and independence.

### Bootstrapping Phase

Morpheus' Fair Launch began on **February 8, 2024**, marking the start of a 90-day Liquidity Bootstrapping phase. The objective of this phase was to generate yield for Morpheus using the [Techno Capital Machine](/tokenomics/techno-capital-machine) model to have sufficient liquidity to fulfill the utility functions of the network.

During this period, [Capital Providers](/meet-morpheus/morpheus-contributors#capital-providers) deposited their stETH into Morpheus [Smart Contract](broken://pages/ZEIeRmT0g61CFPQQbNyE#stake) and in return, rewarded with 24% of the daily MOR emissions.&#x20;

By the end of the 90 days, nearly **800 stETH** had been generated.

<figure><img src="/files/0y6hAXc1bYVdmS6LPMUh" alt=""><figcaption><p>Liquidity Bootstrapping Phase</p></figcaption></figure>

### AMM Initiation Phase

On **May 8th 2024**, yield earned by Morpheus from Capital Providers was successfully paired with MOR tokens taken from [Protection Fund](/security-audits/protection-fund) emissions and deployed as concentrated liquidity in the [wETH/MOR](https://app.uniswap.org/explore/tokens/arbitrum/0x092baadb7def4c3981454dd9c0a0d7ff07bcfc86) pair on the Uniswap DEX on the Arbitrum chain. \
\
To maintain market stability, the liquidity range was adjusted weekly, gradually transitioning to a full range. The stETH (converted to wETH) yield generated during this period was periodically added to the liquidity pool, further supporting fair price discovery and enhancing market activity.

### Long-Term Protocol-Owned Liquidity

Following the AMM Initiation Phase, a portion of the stETH yield is used to market buy MOR tokens, while the remaining stETH (converted to wETH) is locked as **Protocol-Owned Liquidity**, in alignment with the guidelines outlined in the Morpheus Whitepaper.

Initially, 50% of the MOR was used to deepen liquidity during the bootstrap phase. As liquidity solidifies, the strategy shifts to buying 75% MOR to drive demand and increase token scarcity.

Yield generated by Capital Providers utilizes this way:

* 25% to add as Protocol-Owned Liquidity.
* 25% to buy MOR and add as Protocol-Owned Liquidity.
* 25% to buy and burn MOR, reducing circulating supply.
* 25% to buy and lock MOR for [Epoch 2 tail emissions](/tokenomics/mor-emissions#tail-emissions) until 2040.

Eventually, the strategy could move to 100% MOR buyback when liquidity is deemed sufficient.

### Future of the Protocol-Owned Liquidity

Morpheus is **chain-agnostic by design** and will gradually expand to multiple chains, enabling the acceptance of a wider variety of yield-bearing assets for capital provision.&#x20;

With growing volumes and liquidity on Base, it has been selected as the second chain for **Protocol-Owned Liquidity**. The liquidity is deployed on [**Uniswap Base**](https://app.uniswap.org/explore/tokens/base/0x7431ada8a591c955a994a21710752ef9b882b8e3).

To further diversify and enhance PoL streams, the protocol has introduced small fees for various ecosystem elements. Currently, there is a **0.35% fee** applied to the yield generated by [MOR20-launched](/tokenomics/techno-capital-machine/mor-20-fair-launch-standard) applications and withdrawals made by participants in the Builder rewards bucket.

There are ongoing discussions on ways to strengthen Protocol-Owned Liquidity, everyone is invited to [join and share their ideas. ](https://discord.com/channels/1151741790408429580/1167520881908666569)


# Power Factor Multiplier

Power Factor was introduced as a community initiative to address the negative feedback loop within the Capital Providers bucket and to distinguish genuine contributors from short-term opportunists.

In exchange for locking their future MOR rewards for a specific period, contributors receive a **"Power Factor",** a multiplier applied to the calculation of their MOR rewards. In simple terms, Morpheus contributors earn more rewards now, but can only claim them at a later date.

The Power Factor mirrors the dilution rate that a contributor experiences while staking MOR.

It’s important to note that [MOR daily emissions](/tokenomics/mor-emissions) do not increase as the Power Factor only affects the contributor's share within one of the four contributor pools.

{% hint style="info" %}
MOR Rewards Lock does not affect a Capital Contributor's ability to withdraw their stETH (beyond the standard 7-day period), only the claiming of MOR rewards is delayed. However, once a Contributor withdraws their stETH, their Power Factor no longer applies.
{% endhint %}

<figure><img src="/files/uUrHatZx9kIFEfyZMq9f" alt=""><figcaption><p>MOR Power Factor Chart</p></figcaption></figure>

Full details including Power Factor calculation formula and the MOR Rewards Staking implementation for each contributor's bucket are available in [Morpheus Request for Comments 42](https://github.com/MorpheusAIs/MRC/blob/main/IN%20PROGRESS/MRC42.md).

Answers to frequently asked questions can be found [here.](/tokenomics/power-factor-multiplier)

{% hint style="info" %}
Capital Providers have a default **90-day claim vesting** for MOR rewards. \
Each time a user deposits stETH, they are able to claim their MOR rewards after 90 days, unless they choose to stake for a longer period. Subsequent claims are also be available every 90 days following each claim or deposit.
{% endhint %}


# Referral Program

Morpheus grows through the community — not ads or centralized marketing.\
That’s why the referral program rewards those who bring new Capital Providers into the ecosystem.

👉 **Earn up to a 15% bonus in MOR emissions** when others deposit using your referral address.

The program is **fully on-chain, trustless, and transparent**.

***

### How it Works

1. Any community member can use their wallet as a referral address.
2. Capital Providers enter this address when depositing assets into Morpheus Capital.
3. The system tracks deposits and grants the **referrer a virtual stake bonus** based on the total ETH-equivalent deposits made through their referral.

{% hint style="success" %}
💡 Deposits can be made in **stETH, wETH, wBTC, USDC, or USDT** — all converted into **ETH-equivalent** for calculating referral tiers and bonuses.
{% endhint %}

| Tier       | Total Referred Deposits | Referrer Bonus |
| ---------- | ----------------------- | -------------- |
| **Tier 0** | < 1 ETH                 | 3%             |
| **Tier 1** | ≥ 2.5 ETH               | 5%             |
| **Tier 2** | ≥ 25 ETH                | 10%            |
| **Tier 3** | ≥ 62.5 ETH              | 15%            |

### Example Scenarios

A referral deposit of **100 ETH-equivalent**:

* If the referrer is in **Tier 1 (5%)**, they gain **+5 ETH-equivalent virtual stake** added to their balance.
* At **Tier 3 (15%)**, that same deposit grants the referrer a **+15 ETH-equivalent boost** — the same as if they had personally deposited 15 ETH, but virtually.

***

### Claiming Rewards

Referral rewards are distributed as part of MOR emissions and can be claimed under the same conditions as Capital rewards.

{% hint style="success" %}
This mechanism **does not increase total emissions** — it only increases the referrer’s share of the existing rewards.
{% endhint %}

***

### Why It Matters

* ✅ **Fair**: All deposits are normalized into ETH-equivalent.
* ✅ **Transparent**: Rewards are tracked and visible on-chain.
* ✅ **Aligned**: Growth benefits those who help expand the network.

***

Use your wallet as a referral address today, invite others to deposit, and **grow your MOR rewards as the Morpheus ecosystem expands.**


# Morpheus Inference Marketplace

The **Morpheus Inference Marketplace** is where decentralized AI becomes accessible to everyone. It connects people who need compute power with providers who supply it, all coordinated by smart contracts. Instead of a centralized service, requests and responses flow directly between users and providers in a peer-to-peer system.

### Why Decentralized Inference Matters

Decentralized inference matters because it breaks the dependency on centralized providers who control access, pricing, and availability of AI infrastructure. In a decentralized system, anyone can contribute resources and anyone can use them, creating a more open, resilient, and competitive market. This model reduces single points of failure, keeps costs fair through transparent incentives, and ensures that innovation is not limited by the decisions of a few large players. It’s about shifting power from closed platforms to an open network where inference is a shared, community-driven resource.

### Design

At the center of the marketplace are the **Compute Node contracts**, which:

* Register providers and the models they host
* Match consumers with available providers
* Secure connections through encryption and verifiable on-chain logic

To participate, both sides use a **Proxy-Router** — a lightweight software package that connects to the contracts and manages communication. Once a session is established, the consumer sends requests directly to the provider’s model and receives responses without any middleman.

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

For people who don’t want to run a node, there’s the [**API Gateway**.](https://openbeta.mor.org/) that is free during Beta testing. This gateway:

* Provides a simple API key for access
* Abstracts away the complexity of contracts and routers
* Powers integrations, lite clients, and apps like the **Morpheus Chat App**

Providers benefit by making their models available and earning rewards. Consumers gain flexible access to inference, with pricing based on session time instead of tokens. A reputation system ensures that reliable providers — with strong uptime, speed, and track record — are matched more often.

For those interested in more technical details, see:

* [Intro to Morpheus Compute Node](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Compute%20Providers/Compute%20Node/Intro%20to%20Morpheus%20Compute%20Node.md)
* [Overview of the Morpheus-Lumerin Environment](https://github.com/Lumerin-protocol/Morpheus-Lumerin-Node/blob/main/docs/00-overview.md)

💬 If you have any questions, feel free to ask them in the dedicated channel on [Discord](https://discord.com/channels/1151741790408429580/1167520834139738289).


# API Gateway

The Morpheus Inference Marketplace is currently in **Open Beta**, available at [openbeta.mor.org](https://openbeta.mor.org/). This stage is focused on testing, iteration, and feedback. The marketplace is already functional: providers can register models, and consumers can access them through the API Gateway or by running their own Proxy-Router. The Compute Node contracts on Arbitrum manage the session lifecycle, while encrypted links carry inference requests directly from consumer to provider.

**The technical flow can be summarized as:**

1. A consumer makes an inference request.
2. The Consumer Proxy-Router queries the Compute Node to find a provider.
3. A session is established and encrypted link created.
4. Requests are sent directly between consumer and provider, with usage recorded on-chain.

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

During Open Beta, the API Gateway offers free access with simple API keys. This allows developers to experiment without needing to stake MOR, and it enables users to test different client apps or integrations. Providers can configure their **models-config** file, expose local endpoints (such as `localhost:8000`), or route to external APIs. They are compensated either directly by consumers or through emissions from the Compute bucket when staking is used for access.

#### Why Join the Beta

* **Developers** can experiment with decentralized inference without staking MOR yet.
* **Providers** can test performance, reliability, and compensation models.
* **Builders** can create integrations and apps on top of the system before the full launch.

As Open Beta progresses, access will shift from free API keys toward MOR staking for entry. The provider rating system will expand, ensuring that high-performing providers are matched more often. More apps and integrations will appear, and enterprise users will gain the ability to run fully independent deployments.

This is the moment to get involved: test the system, host a model, build an integration, or explore how decentralized inference fits into your workflow.&#x20;

Everything you do during Open Beta helps shape the future of Morpheus.


# Smart Contracts

Morpheus smart contracts are deployed across Ethereum, Arbitrum, and Base chains, creating a robust multi-chain ecosystem. Capital providers contribute capital on Ethereum, while MOR rewards can be claimed on Arbitrum.

This hybrid model leverages the deep liquidity of yield-bearing on Ethereum, while benefiting from the lower transaction costs on Arbitrum and Base for the MOR token.

### <mark style="color:purple;">E</mark><mark style="color:purple;">**thereum:**</mark>

**MOR Token:** [0xcbb8f1bda10b9696c57e13bc128fe674769dcec0](https://etherscan.io/address/0xcbb8f1bda10b9696c57e13bc128fe674769dcec0)&#x20;

**Community Multisignature Account:** [0x1FE04BC15Cf2c5A2d41a0b3a96725596676eBa1E](https://etherscan.io/address/0x1FE04BC15Cf2c5A2d41a0b3a96725596676eBa1E) or [MOR.ETH](https://etherscan.io/name-lookup-search?id=mor.eth)

### <mark style="color:purple;">**Arbitrum:**</mark>

**MOR Token:** [0x092baadb7def4c3981454dd9c0a0d7ff07bcfc86](https://arbiscan.io/token/0x092baadb7def4c3981454dd9c0a0d7ff07bcfc86) &#x20;

**Community Multisignature Account:** [0x151c2b49CdEC10B150B2763dF3d1C00D70C90956](https://arbiscan.io/address/0x151c2b49CdEC10B150B2763dF3d1C00D70C90956)

**MOR Burn Address:** [0x000000000000000000000000000000000000dead](https://arbiscan.io/token/0x092baadb7def4c3981454dd9c0a0d7ff07bcfc86?a=0x000000000000000000000000000000000000dead)

**MOR Lock Address:** [0xb1972e86b3380fd69dcb395f98d39fbf1a5f305a](https://arbiscan.io/address/0xb1972e86b3380fd69dcb395f98d39fbf1a5f305a)

**Builder Emissions Treasury:** [0xbD5D3A6D2Ced315dBded2a434164A268B122694A](https://arbiscan.io/address/0xbD5D3A6D2Ced315dBded2a434164A268B122694A)

**Builders Contract:** [0xC0eD68f163d44B6e9985F0041fDf6f67c6BCFF3f](https://arbiscan.io/address/0xC0eD68f163d44B6e9985F0041fDf6f67c6BCFF3f)

**Builder Rewards Treasury:** [0xCBE3d2c3AdE62cf7aa396e8cA93D2A8bff96E257](https://arbiscan.io/address/0xCBE3d2c3AdE62cf7aa396e8cA93D2A8bff96E257)

### <mark style="color:purple;">**Base:**</mark>

**MOR Token:** [0x7431ada8a591c955a994a21710752ef9b882b8e3](https://basescan.org/token/0x7431ada8a591c955a994a21710752ef9b882b8e3)&#x20;

**Community Multisignature Account:** [0xf3ef00168dd40eae68a7e670d56c7b8724e0c183](https://basescan.org/address/0xf3ef00168dd40eae68a7e670d56c7b8724e0c183)

**Builders Contract:** [0x42BB446eAE6dca7723a9eBdb81EA88aFe77eF4B9](https://basescan.org/address/0x42BB446eAE6dca7723a9eBdb81EA88aFe77eF4B9)

**Builder Rewards Treasury:** [0x9eba628581896ce086cb8f1A513ea6097A8FC561](https://basescan.org/address/0x9eba628581896ce086cb8f1A513ea6097A8FC561)

## <mark style="color:green;">**Сompute contracts**</mark>

<mark style="color:purple;">**Arbitrum:**</mark>

**Provider Registry:** [0x8621E6b808A3d925533446B767B7BCA6ACCb62a2](https://arbiscan.io/address/0x8621E6b808A3d925533446B767B7BCA6ACCb62a2)

**Model Registry:** [0x2E96cEF46D2a82e63570b538EF4aB697a09a3996](https://arbiscan.io/address/0x2E96cEF46D2a82e63570b538EF4aB697a09a3996)

**Marketplace:** [0xc371404682A2E02C3b46814261BEE615E57F48a8](https://arbiscan.io/address/0xc371404682A2E02C3b46814261BEE615E57F48a8)

**Session Router:** [0xAB493D93Bd9C93C7590865df82F4e09F3dF96D4C](https://arbiscan.io/address/0xAB493D93Bd9C93C7590865df82F4e09F3dF96D4C)

**Delegate Registry:** [0x00000000000000447e69651d841bD8D104Bed493](https://arbiscan.io/address/0x00000000000000447e69651d841bD8D104Bed493)

**Compute Rewards Treasury:** [0x5160C0311A95E0A1072FA85Df23712A7BA1cD4b1](https://arbiscan.io/address/0x5160C0311A95E0A1072FA85Df23712A7BA1cD4b1)

**Compute Emissions Treasury:** [0x18b68344a9d235185ee3ec53d28e83260cc0282f](https://arbiscan.io/address/0x18b68344a9d235185ee3ec53d28e83260cc0282f)&#x20;

## <mark style="color:green;">**Сapital contracts**</mark>

<mark style="color:purple;">**Ethereum:**</mark>

**DepositPool(stETH):** [0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790](https://etherscan.io/address/0x47176b2af9885dc6c4575d4efd63895f7aaa4790)

**DepositPool(wETH):** [0x9380d72aBbD6e0Cc45095A2Ef8c2CA87d77Cb384](https://etherscan.io/address/0x9380d72abbd6e0cc45095a2ef8c2ca87d77cb384)

**DepositPool(wBTC):** [0xdE283F8309Fd1AA46c95d299f6B8310716277A42](https://etherscan.io/address/0xde283f8309fd1aa46c95d299f6b8310716277a42)

**DepositPool(USDC):** [0x6cCE082851Add4c535352f596662521B4De4750E](https://etherscan.io/address/0x6cce082851add4c535352f596662521b4de4750e)

**DepositPool(USDT):** [0x3B51989212BEdaB926794D6bf8e9E991218cf116](https://etherscan.io/address/0x3b51989212bedab926794d6bf8e9e991218cf116)

**L1SenderV2:** [0x2Efd4430489e1a05A89c2f51811aC661B7E5FF84](https://etherscan.io/address/0x2efd4430489e1a05a89c2f51811ac661b7e5ff84)

**ChainLinkDataConsumer:** [0xd182263d06FDC463c96190005D6359CC3d3Bbc5e](https://etherscan.io/address/0xd182263d06fdc463c96190005d6359cc3d3bbc5e)

**RewardPool:** [0xb7994dE339AEe515C9b2792831CD83f3C9D8df87](https://etherscan.io/address/0xb7994de339aee515c9b2792831cd83f3c9d8df87)

**Distributor:** [0xDf1AC1AC255d91F5f4B1E3B4Aef57c5350F64C7A](https://etherscan.io/address/0xdf1ac1ac255d91f5f4b1e3b4aef57c5350f64c7a)

**LinearDistributionIntervalDecrease:** [0xfb1a7d49ceb0ee8c929d67eb9762366506a4825c](https://etherscan.io/address/0xfb1a7d49ceb0ee8c929d67eb9762366506a4825c)

**LockMultiplierMath:** [0x345b8b23c38f70f1d77560c60493bb583f012cb0](https://etherscan.io/address/0x345b8b23c38f70f1d77560c60493bb583f012cb0)

**LogExpMath:** [0x345b8b23c38f70f1d77560c60493bb583f012cb0](https://etherscan.io/address/0x345b8b23c38f70f1d77560c60493bb583f012cb0)

**ReferrerLib:** [0x9a397c638bd9611539e7992b32e206102e6d2965](https://etherscan.io/address/0x9a397c638bd9611539e7992b32e206102e6d2965)

\
Full details on the smart contracts can be found in the next section.&#x20;

Source code is available in [**GitHub Repository**](https://github.com/MorpheusAIs/SmartContracts)<br>


# Documentation

At genesis, the Morpheus network utilizes six smart contracts, including the MOR token itself, used to incentivize key contributors to the network, as well as contracts enabling the [Techno Capital Machine](/tokenomics/techno-capital-machine) mechanism functioning.&#x20;

### **Morpheus Smart Contracts Set**

* [`MOROFT`](/smart-contracts/documentation/mor-oft) – the Morpheus token, a [LayerZero Omnichain Fungible Token](https://docs.layerzero.network/v2/developers/evm/oft/quickstart) (OFT)
* [`Distribution Protocol`](https://gitbook.mor.org/~/revisions/3ulU7lsttK8DsMz9IH4e/smart-contracts/documentation/distribution-protocol/v7-protocol) – used to lock capital for the Techno Capital Machine and claim rewards
* [`LinearDistributionIntervalDecrease`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/libs/lineardistributionintervaldecrease) – a library for calculating rewards
* [`L1Sender`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/l1senderv2/l1senderv3) – sends MOR claiming (minting) requests; wraps and transfers stETH to Arbitrum
* [`L2MessageReceiver`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/l2messagereceiver) – receives and processes MOR claiming (minting) requests on L2
* [`L2TokenReceiverV2` ](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/l2tokenreceiverv2)– receives wstETH and manages Protocol-Owned Liquidity on L2

With the exception of the MOR token and `LinearDistributionIntervalDecrease` library, all contracts utilize the [UUPS proxy pattern](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable) to enable upgradeability and are owned by the [Morpheus multisignature accounts](/smart-contracts/multisig) on their respective chains.\
\
Within the contracts, **deposit token** is used to refer to the token deposited by Capital Providers (stETH) or its wrapped counterpart (wstETH), while **reward token** refers to the MOR token.

### Audits

The Morpheus smart contracts were audited [by Renascence](https://github.com/MorpheusAIs/Docs/blob/main/Security%20Audit%20Reports/Distribution%20Contract/Distribution%20V2%20Audit%20%7C%20Renascence.pdf) and later subject to a public [CodeHawks audit](https://www.codehawks.com/contests/clrzgrole0007xtsq0gfdw8if).


# Compute protocol

{% content-ref url="/pages/l2sGB0WA7LwJ3PILTDwX" %}
[Deployed contracts](/smart-contracts/documentation/compute-protocol/deployed-contracts)
{% endcontent-ref %}


# Deployed contracts

## Mainnet

### Arbitrum One

<table><thead><tr><th width="203.89453125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>Lumerin Diamond</code>  </td><td><a href="https://arbiscan.io/address/0xde819aaee474626e3f34ef0263373357e5a6c71b"><kbd>0xde819aaee474626e3f34ef0263373357e5a6c71b</kbd></a></td></tr></tbody></table>

### Base

<table><thead><tr><th width="203.17578125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>Lumerin Diamond</code>  </td><td><a href="https://basescan.org/address/0x6aBE1d282f72B474E54527D93b979A4f64d3030a"><kbd>0x6aBE1d282f72B474E54527D93b979A4f64d3030a</kbd></a></td></tr><tr><td><code>DelegateFactory</code></td><td><a href="https://basescan.org/address/0x1b48365e33802943b5d98954efabd366f04ff924#readProxyContract"><kbd>0x1B48365e33802943b5D98954EFABD366f04FF924</kbd></a></td></tr></tbody></table>

## Testnet

### Arbitrum Sepolia

<table><thead><tr><th width="203.17578125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>Lumerin Diamond</code>  </td><td><a href="https://sepolia.arbiscan.io/address/0xb8C55cD613af947E73E262F0d3C54b7211Af16CF"><kbd>0xb8C55cD613af947E73E262F0d3C54b7211Af16CF</kbd></a></td></tr></tbody></table>

### Base Sepolia

<table><thead><tr><th width="203.17578125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>Lumerin Diamond</code>  </td><td><a href="https://sepolia.basescan.org/address/0x6e4d0B775E3C3b02683A6F277Ac80240C4aFF930"><kbd>0x6e4d0B775E3C3b02683A6F277Ac80240C4aFF930</kbd></a></td></tr><tr><td><code>DelegateFactory</code></td><td><a href="https://sepolia.basescan.org/address/0xbc0b53a618e7f83baf30e53c195cd9c44083f936"><kbd>0xbc0b53a618e7f83baf30e53c195cd9c44083f936</kbd></a></td></tr></tbody></table>


# Distribution protocol

The protocol is deployed on both Ethereum and Arbitrum One networks. It is designed to operate in a cross-chain environment and uses bridging mechanisms and cross-chain messaging to communication between chains.

## Changelog

#### v1

The base protocol was deployed, enabling stETH staking on the Ethereum network and MOR reward on Arbitrum One. LayerZero is used for cross-chain messaging between the networks, allowing user actions to be transmitted and MOR rewards to be minted on L2. The Arbitrum Bridge is used to transfer yield generated from stETH to L2. The protocol includes a built-in MOR token emission logic distributed across multiple reward buckets: Capital (pool `0`), Providers, Builders, Compute, Coders, and Protection. The main public bucket, called Capital, is available for general user staking, while other buckets are private and managed by the contract owner.

#### v2

Introduced the ability for Capital stakers to boost their MOR rewards using a Power Factor. A user can choose to lock the mint of their rewards on L2 until a specific point in time. In return, their stake receives a multiplier calculated from a nonlinear curve based on the lock duration. This allows users to voluntarily delay their reward access in exchange for higher MOR yields, a multiplier of up to 10.7x is applied.

#### v3

Extended the Power Factor logic to private buckets. These participants can now also receive boosted rewards through locking, similar to users in the Capital bucket.

#### v4

Added support for lock periods for MOR receives. After staking or claiming rewards, MOR tokens may be temporarily locked and unavailable for claim for a configurable period of time. The lock duration is defined separately for each bucket and is set by the contract owner. Initially, these are set to 90 days for the capital pool  and 0 for all other pools.

#### v5 - current

Introduced a referral program. It allows users to act as referrers and earn an additional multiplier on their rewards. The yield of referees is influenced by the total amount of tokens staked by users they have referred. [MRC45](https://github.com/MorpheusAIs/MRC/blob/main/IMPLEMENTED/MRC45.md).

#### v7 - proposed

Introduces the ability to stake not only stETH, but also other tokens. The yield from these additional tokens will be provided through integration with the Aave protocol. Reward calculation for users is now based not only on their stake and multipliers, but also on the actual yield performance of the staked token.

## Main docs

{% content-ref url="/pages/zceZGO1ppf8eABUR3RuJ" %}
[v5 Protocol](/smart-contracts/documentation/distribution-protocol/v5-protocol)
{% endcontent-ref %}

{% content-ref url="/pages/IvKbFIr9I0n1Fu3WWzep" %}
[v7 Protocol](/smart-contracts/documentation/distribution-protocol/v7-protocol)
{% endcontent-ref %}


# v5 Protocol

## Introduction

The primary goal of the v5 protocol is to ensure accurate distribution of MOR tokens among stakers of various buckets based on their staked stETH.&#x20;

Capital stakers (Capital bucket) deposit stETH on the Ethereum network through this protocol for a some period of time, in exchange for receiving yield in the form of MOR tokens on the Arbitrum One network utilizing LayerZero for cross-chain messaging. The yield is calculated based on the user’s stake, the total stake across all users, and the overall reward pool. A user’s yield can be increased through participation in the referral program or by utilizing a power factor.

Other buckets **do not** stake stETH directly into the smart contract. Instead, the contract owner allocates reward shares to specific addresses. These addresses, following a similar logic to capital stakers, can claim MOR tokens based on their assigned share.

In turn, the Morpheus protocol earns yield from the stETH deposited by users. This yield is transferred to Arbitrum using the Arbitrum Bridge. On L2, the yield can optionally be converted into MOR tokens to increase liquidity in the Uniswap pool.

Each bucket has its own separate reward pool, and these do not overlap. This ensures that capital stakers are not mixed with other participant groups, maintaining clear reward boundaries and fair distribution within each category.


# Contracts

## Protocol architecture

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

## Ethereum core contracts

### [DistributionV5](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/distributionv5)

The central smart contract of the protocol, responsible for calculating, allocating, and emitting MOR tokens to predefined user buckets. These buckets represent different participant groups within the ecosystem: Capital, Providers, Builders, Compute, Coders, and Protection. The contract’s reward mechanism is based on user stake amounts (denominated in stETH) and is influenced by various multipliers, including time locks and referral bonuses. It features a linear emission decay model powered by the `LinearDistributionIntervalDecrease` library, ensuring a controlled and gradually decreasing token distribution over time. This supports long-term sustainability and prevents over-inflation. The contract integrates with `L1Sender` to relay reward and staking data to L2, and it uses `LogExpMath` and `ReferrerLib` libraries to perform advanced reward calculations and referral logic.

### [L1Sender](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/l1sender)

Handles cross-chain messaging from Ethereum (L1) to Arbitrum (L2). It sends reward data to the `L2MessageReceiver` via LayerZero, triggering the minting of MOR tokens. Additionally, it transfers stETH-based yield earned by the Morpheus protocol to `L2TokenReceiverV2` using the Arbitrum Bridge. This ensures that both reward data and actual assets flow securely to the L2 environment for distribution and liquidity support.

## Arbitrum One core contracts

### [L2MessageReceiver](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/l2messagereceiver)

The contract acts as the trusted endpoint for receiving messages from L1 via LayerZero. Its primary role is to securely handle incoming data about MOR rewards sent from `L1Sender`. Once a valid message is received, the contract processes the payload and execute the token minting logic. It ensures seamless and verifiable communication between the two chains, preserving trust and synchronization of reward distribution.

### [L2TokenReceiverV2](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/l2tokenreceiverv2)

The contract responsible for handling inbound token transfers from L1, specifically the yield earned in stETH. This contract works in tandem with Arbitrum Bridge to securely receive cross-chain token bridged assets. Once received, these assets (typically wstETH) can be swapped or utilized within the L2 environment—for example, converted into MOR tokens and added to liquidity pools like Uniswap to support the protocol’s token economy. It serves as a bridge landing point for real yield, enabling efficient liquidity flow into the L2 network.

## Libs

### LinearDistributionIntervalDecrease

This library manages the linear emission *decay* mechanism used to gradually reduce the amount of tokens distributed over time. It defines how the available reward amount decreases with each interval (e.g., daily, weekly), allowing the protocol to implement a predictable emission schedule. Used by the DistributionV5 contract to calculate how many MOR tokens can currently be distributed based on the time elapsed since the start of the distribution schedule.

### LockMultiplierMath

This library provides logic to compute  multipliers based on how long a user locks their staked tokens (stETH). The longer the lock duration, the higher the multiplier — encouraging users to stake for longer periods and reinforcing long-term alignment with the protocol.

### LogExpMath

Provides high-precision mathematical functions for logarithmic and exponential operations, which are crucial in many DeFi reward calculations (e.g., bonding curves, APY adjustments, dynamic pricing). Solidity lacks native high-precision log/exp functions, so this library ensures safe and accurate computations.

### ReferrerLib

Implements referral program logic, enabling the protocol to reward stakers for inviting others. It tracks referral relationships, determines the eligibility of rewards.

## Periphery

### **Uniswap V3**&#x20;

Used to manage MOR token liquidity on Arbitrum. These contracts allow the protocol to add/remove liquidity, perform swaps, and rebalance pools efficiently.

Used contracts:

* `SwapRouter` - facilitates MOR/ETH or MOR/stETH token swaps (and vice versa) within the Uniswap V3 ecosystem.
* `NonfungiblePositionManager` - manages liquidity positions represented as NFTs in Uniswap V3.

Links:

* <https://docs.uniswap.org/contracts/v3/overview>
* <https://docs.uniswap.org/contracts/v3/reference/deployments/ethereum-deployments>

### Layer Zero V1

Cross-chain messaging protocol used to connect Ethereum (L1) and Arbitrum (L2).

Used contracts:

* `EndpointV1` - acts as the primary messaging interface between L1 and L2.

Links:

* <https://docs.layerzero.network/v1/developers/evm/evm-guides/getting-started>
* <https://docs.layerzero.network/v1/deployments/deployed-contracts?chains=arbitrum%2Cethereum>

### Arbitrum Bridge

Used to transfer native or ERC-20 tokens between Ethereum and Arbitrum.

Used contracts:

* `L1GatewayRouter`  - sends token bridging instructions from Ethereum.
* `L2GatewayRouter` - receives tokens on Arbitrum and finalizes transfer.

Links:

* <https://docs.arbitrum.io/welcome/get-started>
* <https://docs.arbitrum.io/build-decentralized-apps/reference/contract-addresses>

### OpenZeppelin

Used extensively across contracts to support secure access control and upgradeability:

* `OwnableUpgradeable` – enables ownership access control.
* `UUPSUpgradeable` – facilitates contract upgradeability via the UUPS (Universal Upgradeable Proxy Standard) pattern.

Links:

* <https://docs.openzeppelin.com/contracts/4.x/access-control>
* <https://docs.openzeppelin.com/contracts/4.x/api/proxy>


# DistributionV5

## Introduction

The `DistributionV5` contract is the core logic and coordination layer of the  protocol on Ethereum. It is responsible for managing all aspects of user staking, calculating reward entitlements, handling multipliers, enforcing locking logic, and coordinating cross-chain reward delivery via LayerZero.

### Key Responsibilities

1. User staking and tracking:
   * Allows users to deposit stETH into the protocol’s staking system.
   * Supports custom staking options like specifying a `claimLockEnd_` (lock duration) and setting a referrer address to benefit from referral multipliers.
   * Keeps detailed records of each user’s stake, including lock periods, multipliers.
2. Reward distribution logic:
   * Computes user reward entitlements based on their stake amount, stake duration, pool configuration, referral status, and global reward emission rates.
   * Allocates rewards across multiple reward pools (“buckets”), such as Capital, Builder, Compute, Code, and Protection — each with independent reward supply and logic.
   * Ensures fair, non-overlapping distribution across these groups.
3. Power factor and referral system:
   * Integrates a lock-based power factor system, rewarding users who lock their claim for longer periods.
   * Implements a referral tier system, where both the referrer and referred user can receive enhanced yield.
   * Dynamically recalculates multipliers on every stake update, using precise mathematical formulas defined in external libraries (e.g., `LinearDistributionIntervalDecrease`, `ReferrerLib`).
4. Cross-chain reward dispatch:
   * After reward calculation, it communicates with the `L1Sender` contract to send reward payloads to Arbitrum (L2).
   * Uses LayerZero to send encoded reward data to the `L2MessageReceiver`, where actual MOR tokens are minted and delivered to users.
5. Data and State Management:
   * Maintains granular, bucket-specific data about user stakes, referral structures, and global reward metrics.
   * Optimizes gas costs and ensures integrity by storing only the necessary state variables and leveraging internal libraries for math and reward logic.

## Storage

### isNotUpgradeable

Returns true if the contract no longer supports upgrades to a new version.

```solidity
bool public isNotUpgradeable;
```

### depositToken

The stETH token address, see the LIDO [doc](https://docs.lido.fi/deployed-contracts/).

```solidity
address public depositToken;
```

### l1Sender

The `L1Sender` contract address.

```solidity
address public l1Sender;
```

### pools

Contain information about MOR reward pools for buckets. `pools[<poolId>]`.

```solidity
Pool[] public pools;
 
struct Pool {
  uint128 payoutStart;
  uint128 decreaseInterval;
  uint128 withdrawLockPeriod;
  uint128 claimLockPeriod;
  uint128 withdrawLockPeriodAfterStake;
  uint256 initialReward;
  uint256 rewardDecrease;
  uint256 minimalStake;
  bool isPublic;
}
```

| Name                           | Description                                                                         |
| ------------------------------ | ----------------------------------------------------------------------------------- |
| `payoutStart`                  | The unix epoch timestamp in seconds when the pool starts to pay out rewards.        |
| `decreaseInterval`             | The interval in seconds between reward decreases.                                   |
| `withdrawLockPeriod`           | The period in seconds when the user can't withdraw his stake.                       |
| `claimLockPeriod`              | The period in seconds when the user can't claim his rewards after the `payoutStart` |
| `withdrawLockPeriodAfterStake` | The period in seconds when the user can't withdraw his stake after staking.         |
| `initialReward`                | The initial MOR reward for the bucket.                                              |
| `rewardDecrease`               | The MOR reward decrease per `decreaseInterval`.                                     |
| `minimalStake`                 | The minimal stake amount                                                            |
| `isPublic`                     | `true` - for Capital bucket, `false` for others.                                    |

### poolsData

Contain additional internal information about MOR reward pools for buckets. `poolsData[<poolId>]`.

```solidity
mapping(uint256 => PoolData) public poolsData;

struct PoolData {
  uint128 lastUpdate;
  uint256 rate;
  uint256 totalVirtualDeposited;
}
```

| Name                    | Description                                                      |
| ----------------------- | ---------------------------------------------------------------- |
| `lastUpdate`            | The unix epoch timestamp when the rate was updated.              |
| `rate`                  | The current pool coefficient, used to calculate awards.          |
| `totalVirtualDeposited` | The total amount of stETH deposited in the pool with multiplier. |

### usersData

Stores all staking-related data for users.  `usersData[<stakerAddress>][<poolId>].`

```solidity
mapping(address => mapping(uint256 => UserData)) public usersData;

struct UserData {
  uint128 lastStake;
  uint256 deposited;
  uint256 rate;
  uint256 pendingRewards;
  uint128 claimLockStart;
  uint128 claimLockEnd;
  uint256 virtualDeposited;
  uint128 lastClaim;
  address referrer;
}
```

| Name             | Description                                                                                                                                           |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| lastStake        | The unix epoch timestamp when the user stake was last.                                                                                                |
| deposited        | The amount of staked stETH.                                                                                                                           |
| rate             | The last user reward rate, used to calculate awards.                                                                                                  |
| pendingRewards   | The last saved MOR rewards for the user. This value is updated when stake, withdraw or claim from the user account occurs. It is not the final award. |
| claimLockStart   | MOR rewards lock period starts at this timestamp.                                                                                                     |
| claimLockEnd     | MOR rewards lock period end at this timestamp.                                                                                                        |
| virtualDeposited | The amount of staked stETH, with multipliers.                                                                                                         |
| lastClaim        | The last claim timestamp.                                                                                                                             |
| referrer         | The referrer address.                                                                                                                                 |

### totalDepositedInPublicPools

Tracks the total amount of stETH deposited in the public pools (specifically the capital bucket).

### poolsLimits

Defines pool-specific limits and parameters. `poolsLimits[<poolId>]` - limits for the capital bucket.

```solidity
mapping(uint256 => PoolLimits) public poolsLimits;

struct PoolLimits {
  uint128 claimLockPeriodAfterStake;
  uint128 claimLockPeriodAfterClaim;
}
```

| Name                        | Description                                                             |
| --------------------------- | ----------------------------------------------------------------------- |
| `claimLockPeriodAfterStake` | The period in seconds when the staker can't claim tokens after staking. |
| `claimLockPeriodAfterClaim` | The period in seconds when the user can't claim tokens after claiming   |

### referrerTiers

Stores referral reward tiers per pool. `referrerTiers[<poolId>][<tierIndex>]`.

```solidity
mapping(uint256 => ReferrerTier[]) public referrerTiers;

struct ReferrerTier {
  uint256 amount;
  uint256 multiplier;
}
```

| Name         | Description                                                      |
| ------------ | ---------------------------------------------------------------- |
| `amount`     | The minimal token amount for the tier                            |
| `multiplier` | The multiplier for the tier, where 1% = 0.01 \* 10<sup>25</sup>. |

### referrersData

Tracks referral activity per user and pool. `referrersData[<stakerAddress>][<poolId>]`.

```solidity
mapping(address => mapping(uint256 => ReferrerData)) public referrersData;

struct ReferrerData {
  uint256 amountStaked;
  uint256 virtualAmountStaked;
  uint256 rate;
  uint256 pendingRewards;
  uint128 lastClaim;
}
```

| Name                | Description                                                              |
| ------------------- | ------------------------------------------------------------------------ |
| amountStaked        | The amount of referred stETH.                                            |
| virtualAmountStaked | The amount of referred stETH, with multipliers.                          |
| rate                | The last referrer reward rate, used to calculate awards.                 |
| pendingRewards      | The last saved MOR rewards for the referrer.  It is not the final award. |
| lastClaim           | The last claim timestamp.                                                |

## Write functions for stakers

### stake

The stake function allows users to deposit stETH into the protocol from the Ethereum network, then the staker will get a share of the rewards.&#x20;

```solidity
stake(
  uint256 poolId_,
  uint256 amount_, 
  uint128 claimLockEnd_, 
  address referrer_
) external;
```

| Name            | Description                                                      |
| --------------- | ---------------------------------------------------------------- |
| `poolId_`       | The reward pool ID.                                              |
| `amount_`       | The stETH amount to stake, where 1 stETH = 10<sup>18.</sup>      |
| `claimLockEnd_` | The unix epoch timestamp in seconds. Use the default zero value. |
| `referrer_`     | The referrer address. Use the default zero address.              |

### withdraw

The withdraw function allows users to retrieve their staked stETH after a withdraw lock period.

```solidity
function withdraw(
  uint256 poolId_, 
  uint256 amount_
) external;
```

| Name      | Description                                                    |
| --------- | -------------------------------------------------------------- |
| `poolId_` | The reward pool ID.                                            |
| `amount_` | The stETH amount to withdraw, where 1 stETH = 10<sup>18.</sup> |

### claim

The claim function enables stakers to receive the MOR tokens they’ve accrued.

```solidity
function claim(
  uint256 poolId_, 
  address receiver_
) external payable;
```

| Name        | Description                             |
| ----------- | --------------------------------------- |
| `poolId_`   | The reward pool ID.                     |
| `receiver_` | The address who will receive MOR on L2. |

### lockClaim

The function to lock rewards and receive claim lock multiplier (power factor). Used when a user has an active stake and wants to receive a multiplier without triggering a new staking transaction.

```solidity
function lockClaim(
  uint256 poolId_,
  uint128 claimLockEnd_
) external poolExists(poolId_);
```

| Name            | Description                          |
| --------------- | ------------------------------------ |
| `poolId_`       | The reward pool ID.                  |
| `claimLockEnd_` | The unix epoch timestamp in seconds. |

### claimReferrerTier

The function enables referrer to receive the MOR tokens they’ve accrued.

```solidity
function claimReferrerTier(
  uint256 poolId_, 
  address receiver_
) external payable poolExists(poolId_);
```

| Name        | Description                             |
| ----------- | --------------------------------------- |
| `poolId_`   | The reward pool ID.                     |
| `receiver_` | The address who will receive MOR on L2. |

## Write functions for contract owner

### Distribution\_init

Initializes the contract. This is a one-time setup function, used during deployment via proxies.

```solidity
function DistributionV5_init(
  address depositToken_,
  address l1Sender_,
  Pool[] calldata poolsInfo_
) external initializer;
```

| Name            | Description                                   |
| --------------- | --------------------------------------------- |
| `depositToken_` | The stETH token address.                      |
| `l1Sender_`     | The `L1Sender` contract address.              |
| `poolsInfo_`    | The rewards pools info (buckets reward info). |

### createPool

The function to create a new reward pool for the bucket.

```solidity
function createPool(Pool calldata pool_) public onlyOwner;
```

| Name    | Description                                 |
| ------- | ------------------------------------------- |
| `pool_` | The rewards pool info (bucket reward info). |

### editPool

The function to edit an existed reward pool for the bucket.

```solidity
function editPool(
  uint256 poolId_,
  Pool calldata pool_
) external onlyOwner poolExists(poolId_);
```

| Name      | Description                                 |
| --------- | ------------------------------------------- |
| `pool_`   | The rewards pool info (bucket reward info). |
| `poolId_` | The reward pool ID.                         |

### editPoolLimits

The function to edit the reward pool limits.

```solidity
function editPoolLimits(
  uint256 poolId_,
  PoolLimits calldata poolLimits_
) external onlyOwner poolExists(poolId_);
```

| Name          | Description            |
| ------------- | ---------------------- |
| `poolId_`     | The reward pool ID.    |
| `poolLimits_` | The pool's limit data. |

### manageUsersInPrivatePool

The function to manage users and their rate in the private pool (not capital bucket). This function specifically controls the user shares in the other buckets.

```solidity
function manageUsersInPrivatePool(
  uint256 poolId_,
  address[] calldata users_,
  uint256[] calldata amounts_,
  uint128[] calldata claimLockEnds_,
  address[] calldata referrers_
) external onlyOwner poolExists(poolId_);
```

| Name             | Description                                   |
| ---------------- | --------------------------------------------- |
| `poolId_`        | The reward pool ID.                           |
| `users_`         | The users addresses.                          |
| `amounts_`       | The virtual staked amount vlaues for `users_` |
| `claimLockEnds_` | The claim lock end values for `users_`.       |
| `referrers_`     | The referrer values for `users_`              |

### editReferrerTiers

The function to setup tiers for the refferal system.

```solidity
function editReferrerTiers(
  uint256 poolId_,
  ReferrerTier[] calldata referrerTiers_
) external onlyOwner poolExists(poolId_)
```

| Name             | Description                 |
| ---------------- | --------------------------- |
| `poolId_`        | The reward pool ID.         |
| `referrerTiers_` | The referrer tiers structs. |

### bridgeOverplus

The function transfers the stETH yield from L1 to L2. Returns the unique identifier for the trabsfer operation from the Arbitrum Bridge.

```solidity
function bridgeOverplus(
  uint256 gasLimit_,
  uint256 maxFeePerGas_,
  uint256 maxSubmissionCost_
) external payable onlyOwner returns (bytes memory);
```

| Name                 | Description                                  |
| -------------------- | -------------------------------------------- |
| `gasLimit_`          | The gas limit for the Arbitrum Bridge.       |
| `maxFeePerGas_`      | The max fee per gas for the Arbitrum Bridge. |
| `maxSubmissionCost_` | The max submission cost.                     |

### removeUpgradeability

The function to remove the possibility to upgrade the smart contract.

```solidity
function removeUpgradeability() external onlyOwner;
```

## Read functions

### getPeriodReward

The function to calculate the bucket rewards for the specified period. Returns the reward amount, where 1 MOR = 10<sup>18</sup>.

```solidity
function getPeriodReward(
  uint256 poolId_,
  uint128 startTime_,
  uint128 endTime_
) external view returns (uint256);
```

| Name         | Description                                                      |
| ------------ | ---------------------------------------------------------------- |
| `poolId_`    | The reward pool ID.                                              |
| `startTime_` | The unix timestamp. Start calculate rewards from this timestamp. |
| `endTime_`   | The unix timestamp. End calculate rewards to this timestamp.     |

### getCurrentUserReward

This function calculates the total claimable MOR token rewards for a given staker within a specific bucket, based on their current stake and multipliers. Where 1 MOR = 10<sup>18</sup>.

```solidity
function getCurrentUserReward(
  uint256 poolId_, 
  address user_
) external view returns (uint256);
```

| Name      | Description         |
| --------- | ------------------- |
| `poolId_` | The reward pool ID. |
| `user_`   | The staker address. |

### getCurrentReferrerReward

This function calculates the total claimable MOR token rewards for a given referrer within a specific bucket, based on referrals and tier multipliers. Where 1 MOR = 10<sup>18</sup>.

```solidity
function getCurrentReferrerReward(
  uint256 poolId_, 
  address user_
) public view returns (uint256)
```

| Name      | Description         |
| --------- | ------------------- |
| `poolId_` | The reward pool ID. |
| `user_`   | The staker address. |

### getClaimLockPeriodMultiplier

The function to calculate the power factor for the specified period. Returns the multiplier, where x1 = 10<sup>25</sup>.

```solidity
function getClaimLockPeriodMultiplier(
  uint256 poolId_,
  uint128 claimLockStart_,
  uint128 claimLockEnd_
) public view returns (uint256)
```

| Name              | Description                                                               |
| ----------------- | ------------------------------------------------------------------------- |
| `poolId_`         | The reward pool ID.                                                       |
| `claimLockStart_` | The unix timestamp. Start calculate the power factor from this timestamp. |
| `claimLockEnd_`   | The unix timestamp. End calculate the power factor to this timestamp.     |

### getCurrentUserMultiplier

The function to calculate the power factor and referrer multiplier for the specified staker. Returns the multiplier, where x1 = 10<sup>25</sup>.

<pre class="language-solidity"><code class="lang-solidity"><strong>function getCurrentUserMultiplier(
</strong>  uint256 poolId_, 
  address user_
) public view returns (uint256)
</code></pre>

| Name      | Description         |
| --------- | ------------------- |
| `poolId_` | The reward pool ID. |
| `user_`   | The staker address. |

### getReferrerMultiplier

The function to calculate the tier multiplier for the specified referrer. Returns the multiplier, where x1 = 10<sup>25</sup>.

```solidity
function getReferrerMultiplier(
  uint256 poolId_,
  address referrer_
) public view returns (uint256)
```

| Name        | Description           |
| ----------- | --------------------- |
| `poolId_`   | The reward pool ID.   |
| `referrer_` | The referrer address. |

### overplus

The function to calculate the current protocol yield, the difference between staked stETH and current contract balance.

```solidity
function overplus() external view returns (uint256);
```


# L1Sender

## Introduction

The `L1Sender` contract serves as a critical component in the cross-chain infrastructure of the protocol. Its primary responsibility is to transfer both reward data and yield assets from Ethereum (L1) to Arbitrum (L2), ensuring that users receive accurate MOR token rewards and that the protocol’s yield is available for conversion and distribution on L2.

### Key Responsibilities

1. Cross-chain reward messaging via LayerZero:
   * The contract communicates with the `L2MessageReceiver` on Arbitrum using LayerZero.
   * It packages the user’s reward data (including recipient address and reward amount) and sends it securely across chains.
   * This action is triggered by the `DistributionV5` contract after calculating a user’s rewards.
   * On arrival to L2, the message is decoded, and MOR tokens are minted to the user.
2. Bridging stETH yield via Arbitrum Bridge:
   * The contract manages the bridging of yield generated from stETH held by the Morpheus protocol.
   * It wraps stETH into wstETH and uses Arbitrum Bridge to transfer tokens to the `L2TokenReceiver` contract.
3. Token configuration management:
   * The contract stores configuration data for both deposit and reward tokens:
     * Deposit token: the wrapped stETH token to be bridged.
     * Reward token: LayerZero configuration for sending mint instructions.
   * It handles dynamic updates to these configurations, allowing the protocol to change tokens or gateways without redeploying the contract.
4. Access control and upgradeability:
   * The contract uses OpenZeppelin’s Ownable and UUPSUpgradeable modules to ensure secure ownership and upgradability.
   * Only the `DistributionV5` contract can trigger core functions like sending rewards or bridging yield.
   * The contract supports interface discovery (via ERC165) for interoperability and integration with other tools or protocols.

## Storage

### unwrappedDepositToken

The address of the original deposit token (e.g., stETH) before it is wrapped for cross-chain transfer.

```solidity
address public unwrappedDepositToken;
```

### distribution

The address of the `DistributionV5` contract that handles staking logic and reward distribution.

```solidity
address public distribution;
```

### depositTokenConfig

Configuration details for bridging the stETH token.

```solidity
DepositTokenConfig public depositTokenConfig;

struct DepositTokenConfig {
  address token;
  address gateway;
  address receiver;
}
```

| Name     | Description                                       |
| -------- | ------------------------------------------------- |
| token    | The address of wstETH.                            |
| gateway  | The address of token's gateway, `L1GatewayRouter` |
| receiver | The `L2MessageReceiver` address.                  |

### rewardTokenConfig

Configuration for the LayerZero cross-chain messaging.

```solidity
RewardTokenConfig public rewardTokenConfig;

struct RewardTokenConfig {
  address gateway;
  address receiver;
  uint16 receiverChainId;
  address zroPaymentAddress;
  bytes adapterParams;
}
```

| Name              | Description                                                        |
| ----------------- | ------------------------------------------------------------------ |
| gateway           | The LayerZero `EnpointV1` address.                                 |
| receiver          | The `L2MessageReceiver` address.                                   |
| receiverChainId   | The receiver chain ID, from the LZ doc.                            |
| zroPaymentAddress | The LayerZero ZRO payment address for gas fees.                    |
| adapterParams     | LayerZero adapter parameters used to customize messaging behavior. |

## Write functions for the contract owner

### L1Sender\_\_init

Initializes the contract. This is a one-time setup function, used during deployment via proxies.

```solidity
function L1Sender__init(
 address distribution_,
 RewardTokenConfig calldata rewardTokenConfig_,
 DepositTokenConfig calldata depositTokenConfig_
) external initializer
```

| Name                  | Description                                            |
| --------------------- | ------------------------------------------------------ |
| `distribution_`       | The `DistributionV5` contract address                  |
| `rewardTokenConfig_`  | Configuration for the LayerZero cross-chain messaging. |
| `depositTokenConfig_` | Configuration details for bridging the stETH token.    |

### setDistribution

Allows the contract owner to set or update the address of the DistributionV5 contract.

```solidity
function setDistribution(address distribution_) public onlyOwner
```

| Name            | Description                           |
| --------------- | ------------------------------------- |
| `distribution_` | The `DistributionV5` contract address |

### setRewardTokenConfig

Allows the contract owner to update the LayerZero MOR token configuration used for cross-chain messaging.

```solidity
function setRewardTokenConfig(
  RewardTokenConfig calldata newConfig_
) public onlyOwner
```

| Name                 | Description                                            |
| -------------------- | ------------------------------------------------------ |
| `rewardTokenConfig_` | Configuration for the LayerZero cross-chain messaging. |

### setDepositTokenConfig

Allows the contract owner to update the stETH token configuration.

```solidity
function setDepositTokenConfig(
  DepositTokenConfig calldata newConfig_
) public onlyOwner
```

| Name                  | Description                                         |
| --------------------- | --------------------------------------------------- |
| `depositTokenConfig_` | Configuration details for bridging the stETH token. |

## Write functions for the DistributionV5 contract

### sendDepositToken

Transfers deposit tokens (e.g., stETH wrapped to wstETH) from L1 to L2 using the Arbitrum Bridge.

```solidity
function sendDepositToken(
  uint256 gasLimit_,
  uint256 maxFeePerGas_,
  uint256 maxSubmissionCost_
) external payable onlyDistribution returns (bytes memory)
```

| Name                 | Description                                    |
| -------------------- | ---------------------------------------------- |
| `gasLimit_`          | Gas limit for the L2 execution.                |
| `maxFeePerGas_`      | Max fee for L2 execution.                      |
| `maxSubmissionCost_` | Base submission cost for the retryable ticket. |

### sendMintMessage

Sends a cross-chain message via LayerZero to L2, instructing minting of MOR tokens to the user.

```solidity
function sendMintMessage(
  address user_, 
  uint256 amount_, 
  address refundTo_
) external payable onlyDistribution
```

| Name       | Description                                  |
| ---------- | -------------------------------------------- |
| user\_     | Recipient address on L2.                     |
| amount\_   | Amount of tokens to mint.                    |
| refundTo\_ | Address that receives any unspent msg.value. |

## Read functions

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IL1Sender`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```


# L2MessageReceiver

## Introduction

The `L2MessageReceiver` contract is a crucial component of the protocol's cross-chain reward distribution system. It resides on the Arbitrum network (L2) and is responsible for receiving cross-chain messages from Ethereum (L1) via LayerZero. These messages contain instructions for minting MOR tokens to users who have earned rewards based on their staked stETH in L1.

The contract ensures the secure and accurate minting of MOR tokens by validating incoming messages and calling the minting logic.

### Key Responsibilities

1. LayerZero endpoint integration: listens for and receives payloads sent from the `L1Sender` contract on Ethereum.
2. Message decoding and validation: verifies the origin and decodes message payloads to extract reward details.
3. Reward Distribution: mint the MOR token for the users.

## Storage

### rewardToken

The address of the MOR token contract on Arbitrum.

```solidity
address public rewardToken;
```

### config

The LayerZero config for cross-chain message receiving.

```solidity
Config public config;

struct Config {
  address gateway;
  address sender;
  uint16 senderChainId;
}
```

| Name            | Description                                   |
| --------------- | --------------------------------------------- |
| `gateway`       | The LayerZero `EndpointV1` contract address.  |
| `sender`        | The `L1MessageSender` contract address.       |
| `senderChainId` | The Ethereum chain id fron the LayerZero doc. |

## Write functions for the contract owner

### L2MessageReceiver\_\_init

Initializes the contract during deployment (used with proxies). Can only be called once.

```solidity
function L2MessageReceiver__init() external initializer;
```

### setParams

Sets or updates the MOR token address and LayerZero message config.

```solidity
function setParams(
  address rewardToken_,
  Config calldata config_
) external onlyOwner;
```

| Name           | Description                                             |
| -------------- | ------------------------------------------------------- |
| `rewardToken_` | Address of the MOR token on Arbitrum.                   |
| `config_`      | The LayerZero config for cross-chain message receiving. |

## Write functions for the LayerZero endpoint

### lzReceive

Receives and verifies cross-chain messages from LayerZero. Only callable by the LayerZero endpoint. Delegates execution to `nonblockingLzReceive`.

```solidity
function lzReceive(
    uint16 senderChainId_,
    bytes memory senderAndReceiverAddresses_,
    uint64 nonce_,
    bytes memory payload_
) external
```

| Name                          | Description                                       |
| ----------------------------- | ------------------------------------------------- |
| `senderChainId_`              | ID of the source chain (Ethereum L1).             |
| `senderAndReceiverAddresses_` | Encoded source/destination addresses.             |
| `nonce_`                      | Unique nonce to identify the message.             |
| `payload_`                    | ABI-encoded payload: user address and MOR amount. |

### nonblockingLzReceive

Internal message handler that performs the actual minting logic. Ensures execution does not block LayerZero.

```solidity
function nonblockingLzReceive(
    uint16 senderChainId_,
    bytes memory senderAndReceiverAddresses_,
    bytes memory payload_
) public
```

| Name                          | Description                                       |
| ----------------------------- | ------------------------------------------------- |
| `senderChainId_`              | ID of the source chain (Ethereum L1).             |
| `senderAndReceiverAddresses_` | Encoded source/destination addresses.             |
| `payload_`                    | ABI-encoded payload: user address and MOR amount. |

## Write functions

### retryMessage

Allows retrying a failed cross-chain message. Can be used to recover from transient errors or gas issues.

```solidity
function retryMessage(
    uint16 senderChainId_,
    bytes memory senderAndReceiverAddresses_,
    uint64 nonce_,
    bytes memory payload_
) external
```

| Name                          | Description                               |
| ----------------------------- | ----------------------------------------- |
| `senderChainId_`              | ID of the source chain.                   |
| `senderAndReceiverAddresses_` | Encoded source/destination addresses.     |
| `nonce_`                      | Unique message identifier.                |
| `payload_`                    | Original encoded user address and amount. |


# L2TokenReceiverV2

## Introduction

The `L2TokenReceiverV2` contract is a component of the protocol deployed on Arbitrum (L2). It is responsible for receiving stETH yield sent from Ethereum (L1) via the Arbitrum Bridge. Upon receipt, the yield is stored within the contract and can later be  converted into MOR tokens to support liquidity or distribution.

### Key Responsibilities

* Bridged token receiver: handles incoming stETH/wstETH tokens from the L1Sender contract via Arbitrum Bridge.
* Uniswap v3 Integration: enables the protocol to swap tokens or increase liquidity in Uniswap v3 pools.

***

## Storage

### router

The address of Uniswap v3 `SwapRouter` used for swaps.

```solidity
address public router;
```

### nonfungiblePositionManager

The address of Uniswap v3 `NonfungiblePositionManager` used for adding liquidity and collect fees.

```solidity
address public nonfungiblePositionManager;
```

### firstSwapParams

Holds the current token swap configuration for Uniswap v3 operations. Uses for wstETH/wETH pair.

```solidity
SwapParams public firstSwapParams;

struct SwapParams {
  address tokenIn;
  address tokenOut;
  uint24 fee;
  uint160 sqrtPriceLimitX96;
}
```

| Field               | Description                                                          |
| ------------------- | -------------------------------------------------------------------- |
| `tokenIn`           | Address of the token to be swapped from (input token).               |
| `tokenOut`          | Address of the token to be swapped to (output token).                |
| `fee`               | Uniswap v3 pool fee tier in hundredths of a bip (e.g., 3000 = 0.3%). |
| `sqrtPriceLimitX96` | Optional price limit for swap.                                       |

### secondSwapParams

Holds the current token swap configuration for Uniswap v3 operations. Uses for wETH/MOR pair.

```solidity
SwapParams public secondSwapParams;
```

## Write functions for the contract owner

### L2TokenReceiver\_\_init

Initializes the contract during deployment (used with proxies). Can only be called once.

```solidity
function L2TokenReceiver__init(
    address router_,
    address nonfungiblePositionManager_,
    SwapParams memory secondSwapParams_
) external initializer
```

| Name                          | Description                                                  |
| ----------------------------- | ------------------------------------------------------------ |
| `router_`                     | Address of Uniswap v3 `SwapRouter` contract.                 |
| `nonfungiblePositionManager_` | Address of Uniswap v3 `NonfungiblePositionManager` contract. |
| `secondSwapParams_`           | Swap parameters for the Uniswap wETH/MOR pool.               |

### editParams

Allows the contract owner to update swap parameters and reapprove token allowances.

```solidity
function editParams(
  SwapParams memory newParams_,
  bool isEditFirstParams_
) external onlyOwner
```

| Parameter            | Description                                                             |
| -------------------- | ----------------------------------------------------------------------- |
| `newParams_`         | New `SwapParams` struct for the Uniswap pool.                           |
| `isEditFirstParams_` | `True` - when edit the wstETH/wETH pair. `False` for the wETH/MOR pair. |

***

### swap

Performs a token swap using Uniswap v3 router.

```solidity
function swap(
  uint256 amountIn_,
  uint256 amountOutMinimum_,
  uint256 deadline_,
  bool isUseFirstSwapParams_
) external onlyOwner returns (uint256)
```

| Parameter            | Description                                                            |
| -------------------- | ---------------------------------------------------------------------- |
| `amountIn_`          | Amount of input token to swap.                                         |
| `amountOutMinimum_`  | Minimum expected output amount.                                        |
| `deadline_`          | Expiry timestamp for the transaction.                                  |
| `isEditFirstParams_` | `True` - when use the wstETH/wETH pair. `False` for the wETH/MOR pair. |

Returns: output token amount.

### increaseLiquidityCurrentRange

Adds liquidity to an existing Uniswap NFT position.

```solidity
function increaseLiquidityCurrentRange(
  uint256 tokenId_,
  uint256 amountAdd0_,
  uint256 amountAdd1_,
  uint256 amountMin0_,
  uint256 amountMin1_
) external onlyOwner returns (
  uint128 liquidity_,
  uint256 amount0_,
  uint256 amount1_
 )
```

| Parameter     | Description                 |
| ------------- | --------------------------- |
| `tokenId_`    | NFT ID of the position.     |
| `amountAdd0_` | Desired amount for token 0. |
| `amountAdd1_` | Desired amount for token 1. |
| `amountMin0_` | Minimum amount of token 0.  |
| `amountMin1_` | Minimum amount of token 1.  |

### collectFees

Collects all available fees from a Uniswap NFT liquidity position. Returns the collected amounts of token0 and token1.

```solidity
function collectFees(
  uint256 tokenId_
) external returns (uint256 amount0_, uint256 amount1_)
```

| Parameter  | Description            |
| ---------- | ---------------------- |
| `tokenId_` | NFT ID of the position |

## Read functions

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IL2TokenReceiverV2`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```


# Get started


# Staker functionality

The page describes what a staker can do as part of the protocol.

All of the functions described below are executed on the `DistributionV5` smart contract.

## Stake

The stake function allows users to deposit stETH into the protocol from the Ethereum network, then the staker will get a share of the rewards. Available only for capital stakers.

[The function interface here.](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/distributionv5#stake)

**Notes**

The user can optionally pass a `claimLockEnd_` timestamp during staking, which sets a period **before** which claiming is not allowed. In return, this provides an additional multiplier to the effective stake, increasing the user’s MOR reward potential. The multiplier is recalculated every time a user stakes. If the `claimLockEnd_` timestamp remains unchanged, the multiplier will gradually decrease over time according to a predefined curve. If `claimLockEnd_` was previously set, it does not need to be provided again.

Additionally, the staker may specify a `referrer_` address. This also grants a multiplier to the stake. The user is allowed to pass their own address as the referrer, which still qualifies for the bonus.

The final amount of stETH tokens received by the smart contract may be less than what the staker initially specified. This is due to the internal mechanics of how stETH transfers work — [part of the transfer might be rebased or adjusted by the Lido protocol](https://docs.lido.fi/guides/lido-tokens-integration-guide/#steth-internals-share-mechanics).

The withdrawal of stETH will be locked for a specific period, as defined in the smart contract parameters. This lock duration is reset after each new stake, meaning the withdrawal timer starts over every time the user stakes additional tokens.

Staked stETH remains in the `DistributionV5` contract.

#### Recommendations for a successful transaction

* The smart contract performs a `transferFrom` of stETH from the caller’s address. Therefore, make sure the `DistributionV5` contract has sufficient `allowance` for the stETH token. The `allowance` must be greater than or equal to the amount being staked.
* `poolId_` must be 0, since direct staking is only allowed for the capital bucket.
* `amount_` must be greater than 0 and at least equal to the minimum stake amount defined in the `DistributionV5` contract.
* `claimLockEnd_` must be either 0 (i.e. not setting a lock), or a timestamp greater than the current block timestamp (i.e. in the future).

## Withdraw

The withdraw function allows users to retrieve their staked stETH after a withdraw lock period. Available only for capital stakers.

[The function interface here.](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/distributionv5#withdraw)

**Notes**

Users can only withdraw after the minimum staking period has passed or minimum withdraw timestamp has passed (defined in the smart contract parameters). This does not affect already accrued MOR rewards — users still retain the right to claim them.

If the staker wants to withdraw all of their tokens, they can pass a value greater than their current stake, such as 999,999,999\*10<sup>18</sup>. The contract will interpret this as a request to withdraw the full amount, without requiring the user to specify the exact number of staked tokens.

#### Recommendations for a successful transaction

* The lock period has ended.
* The withdrawal amount must be greater than zero. The user cannot withdraw 0 tokens.
* If partially withdrawing, the remaining stake after withdrawal must not fall below the minimum stake amount defined in the smart contract parameters.

## Claim

The claim function enables stakers to receive the MOR tokens they’ve accrued.

[The function interface here.](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/distributionv5#claim)

**Notes**

The MOR tokens are minted on the Arbitrum network. Claims can be done multiple times and don’t require withdrawing the stake.

Calling this function requires sending additional native ETH, as it utilizes LayerZero and cross-chain communication. The required amount of ETH can be estimated through the LayerZero interface. It is possible to send more than necessary—any excess will be refunded to the user’s account.

#### Recommendations for a successful transaction

* Make sure that the user has rewards available to claim.
* Verify that the claim is unlocked—meaning the lock period after staking and after the last claim has passed. Also ensure that claiming is currently enabled for the Capital bucket.
* Ensure that you are sending a sufficient amount of ETH to cover the LayerZero cross-chain messaging cost.

## Lock claim

The function enables stakers to lock rewards and receive claim lock multiplier (power factor). Used when a user has an active stake and wants to receive a multiplier without triggering a new staking transaction.

[The function interface here.](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/distributionv5#lockclaim)

## Receive stake data and multipliers

Use [`getCurrentUserReward`](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/distributionv5#getcurrentuserreward) to receive the total claimable MOR token rewards for a given user within a specific bucket, based on their current stake and multipliers. Where 1 MOR = 10<sup>18</sup>.

Use [`getCurrentUserMultiplier`](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/distributionv5#getreferrermultiplier) to receive the power factor. Returns the multiplier, where x1 = 10<sup>25</sup>.

Use [`usersData`](/smart-contracts/documentation/distribution-protocol/v5-protocol/contracts/distributionv5#usersdata) to receive the information about user stake, lock periods...


# Protocol Data

The current section describes what data is stored in the smart contract and how to obtain it.

## Distribution V5

#### isNotUpgradeable

Returns true if the contract no longer supports upgrades to a new version.

```solidity
bool public isNotUpgradeable;
```

#### depositToken

The stETH token address, see the LIDO [doc](https://docs.lido.fi/deployed-contracts/).

```solidity
address public depositToken;
```

#### l1Sender

The `L1Sender` contract address.

```solidity
address public l1Sender;
```

#### pools

Contain information about MOR reward pools for buckets, where `pools[0]` - Capital bucket.

```solidity
Pool[] public pools;
 
struct Pool {
  uint128 payoutStart;
  uint128 decreaseInterval;
  uint128 withdrawLockPeriod;
  uint128 claimLockPeriod;
  uint128 withdrawLockPeriodAfterStake;
  uint256 initialReward;
  uint256 rewardDecrease;
  uint256 minimalStake;
  bool isPublic;
}
```

| Name                           | Description                                                                         |
| ------------------------------ | ----------------------------------------------------------------------------------- |
| `payoutStart`                  | The unix epoch timestamp in seconds when the pool starts to pay out rewards.        |
| `decreaseInterval`             | The interval in seconds between reward decreases.                                   |
| `withdrawLockPeriod`           | The period in seconds when the user can't withdraw his stake.                       |
| `claimLockPeriod`              | The period in seconds when the user can't claim his rewards after the `payoutStart` |
| `withdrawLockPeriodAfterStake` | The period in seconds when the user can't withdraw his stake after staking.         |
| `initialReward`                | The initial MOR reward for the bucket.                                              |
| `rewardDecrease`               | The MOR reward decrease per `decreaseInterval`.                                     |
| `minimalStake`                 | The minimal stake amount                                                            |
| `isPublic`                     | `true` - for Capital bucket, `false` for others.                                    |

#### poolsData

Contain additional internal information about MOR reward pools for buckets, where `poolsData[0]` - Capital bucket.

```solidity
mapping(uint256 => PoolData) public poolsData;
 
/**
     * The structure that stores the pool's rate data.
     * @param lastUpdate The timestamp when the pool was updated.
     * @param rate The current reward rate.
     * @param totalVirtualDeposited The total amount of tokens deposited in the pool with multiplier.
     */
struct PoolData {
  uint128 lastUpdate;
  uint256 rate;
  uint256 totalVirtualDeposited;
 }
```

```solidity

    // User storage
    mapping(address => mapping(uint256 => UserData)) public usersData;

    // Total deposited storage
    uint256 public totalDepositedInPublicPools;

    // Pools limits, V4 update
    mapping(uint256 => PoolLimits) public poolsLimits;

    // Referall storage, V5 update
    mapping(uint256 => ReferrerTier[]) public referrerTiers;
    mapping(address => mapping(uint256 => ReferrerData)) public referrersData;
```


# v7 Protocol

## Introduction

Distribution v7 is a modular and scalable protocol designed to aggregate real yield from multiple asset sources, calculate user rewards, and distribute its native token, MOR, across various categories of protocol participants. Its architecture is centered around isolated `DepositPools`, reward generation and distribution logic.

Protocol enables users to stake supported tokens (e.g., stETH, USDC, USDT, cbBTC, wBTC, wstETH, wETH) and earn MOR tokens as rewards. The amount of MOR earned is based on real yield generated through integrated protocols (like Aave) and is influenced by factors such as stake amount, lock duration, and user role within the ecosystem.

## Main concepts

### Staking

Users deposit supported tokens into specific `DepositPool` contracts. Each `DepositPool` supports a single asset and maintains isolated accounting, multipliers, and reward logic. Staked tokens are immediately transferred to the `Distributor`, which manages all yield generation and ensures consistent application of reward mechanics.

### Yield generation

The `Distributor` deposits yield assets such as wBTC, USDC and other into integrated DeFi protocols like Aave to generate real yield. For stETH, however, yield is not derived from lending markets — instead, it relies on Lido’s native rebasing mechanism, which increases the stETH balance over time as staking rewards accrue.

To accurately track and normalize this yield across different token types, the protocol uses the `ChainLinkDataConsumer` contract. This contract fetches real-time price feeds for all supported assets and converts yield into a unified base value (e.g., USD). This ensures fair and transparent reward distribution, regardless of which asset the user stakes.

### MOR reward calculation

The `Distributor` calculates the total MOR reward value for each `DepositPool`. It queries the `RewardPool` contract to determine the amount of MOR to emit over a given time frame, using pre-defined emission curves. Then, it passes that reward amount to each `DepositPool`, which handles reward splitting among its stakers using local multipliers (e.g., power factor, referrals).

### Cross-chain messaging and bridging

The `L1SenderV2` contract manages all cross-chain transfers from Ethereum to Arbitrum:

* It sends MOR reward data to `L2MessageReceiver` on Arbitrum via LayerZero, triggering minting of MOR tokens.
* It transfers real yield (e.g., wstETH) to `L2TokenReceiverV2` via the Arbitrum Bridge.
* It uses Uniswap v3 to swap yield-denominated tokens into wstETH before bridging.

### L2 execution and liquidity management

On Arbitrum, `L2MessageReceiver` and `L2TokenReceiverV2` handle reward minting and liquidity provisioning. MOR tokens can then be distributed to users, added to Uniswap liquidity pools, or used in further reward programs.


# Contracts

This section provides a high-level description of the core contracts in the protocol and their responsibilities within the system.

## Protocol architecture

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

## Ethereum core contracts

### [DepositPool](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool)

The `DepositPool` contract is the legacy core staking vault of the protocol’s earlier architecture. It serves as the primary entry point for users to stake their supported tokens (such as stETH, wBTC...) directly into the system. Each supported deposit token is expected to have a dedicated instance of this contract, isolating accounting, multipliers, and reward logic on a per-token basis. This means that multiplier effects, such as claim lock or referral boosts, apply only within the context of that specific deposit token and do not influence other pools.

This contract does not store the deposited assets itself. Upon staking, tokens are immediately transferred to the Distributor, ensuring management of funds and consistent application of reward mechanics across the protocol.

Each `DepositPool` is tied to a single staking token, enabling modular handling of multiple asset types within the broader system. While the reward logic is centralized in the `Distributor`, the `DepositPool` provides a clean interface for managing user interactions and enforcing protocol-level staking rules at the token level.

### [Distributor v1 and v2](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/distributor)

The `Distributor` contract plays a key  role in the protocol architecture, being responsible for calculating the total MOR token yield for each `DepositPool`. It operates at the pool level rather than the user level and calculate the rewards for the `DepositPool`, which then determines how to distribute MOR among its own stakers.

The `Distributor` integrates with the Aave protocol to deposit user assets (such as USDC, wBTC...) and generate real yield. The contract uses Chainlink oracles to fetch up-to-date price data. This ensures a fair and transparent conversion of real yield into the base token amount. The resulting yield serves as the basis for calculating MOR rewards within the protocol.

Additionally, the `Distributor` interacts directly with the `RewardPool` contract, which contains the emission curve logic for MOR emission. This is necessary to calculate the amount of rewards that need to be distributed over a specific period of time.

### [ChainLinkDataConsumer](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/chainlinkdataconsumer)

The `ChainLinkDataConsumer` contract in the protocol is responsible for normalizing the value of yield accrued from various staking tokens by converting it to a common base token (e.g., USD). It integrates with Chainlink’s decentralized oracle network to fetch reliable and up-to-date price feeds for each supported staking token.

This price data is not used to calculate MOR token emissions directly. Instead, it ensures that yield from different sources (e.g., stETH, wETH, cbBTC...) is fairly and consistently compared and aggregated before being passed into the reward logic. For example, 1 unit of stETH and 1 unit of cbETH might not have equal value — the `ChainLinkDataConsumer` contract provides the conversion rate so their contributions can be measured proportionally in the base currency.

By doing so, it enables accurate, token-agnostic reward accounting and ensures that users are rewarded fairly regardless of which staking asset they contributed.

### [RewardPool](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/rewardpool)

See the documentation for this contract [here](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/rewardpool).

### [L1SenderV2](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/l1senderv2)

Handles cross-chain messaging from Ethereum (L1) to Arbitrum (L2). It sends reward data to the `L2MessageReceiver` via LayerZero, triggering the minting of MOR tokens. Additionally, it transfers stETH-based yield earned by the Morpheus protocol to `L2TokenReceiverV2` using the Arbitrum Bridge. This ensures that both reward data and actual assets flow securely to the L2 environment for distribution and liquidity support.

This contract holds protocol-generated yield in various tokens, depending on active `DepositPool`s. To efficiently convert these assets into wstETH for bridging, the contract integrates with Uniswap v3, leveraging its decentralized exchange capabilities for token swaps.

## Arbitrum One core contracts

### [L2MessageReceiver](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/l2messagereceiver)

The contract acts as the trusted endpoint for receiving messages from L1 via LayerZero. Its primary role is to securely handle incoming data about MOR rewards sent from `L1Sender`. Once a valid message is received, the contract processes the payload and execute the token minting logic. It ensures seamless and verifiable communication between the two chains, preserving trust and synchronization of reward distribution.

### [L2TokenReceiverV2](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/l2tokenreceiverv2)

The contract responsible for handling inbound token transfers from L1, specifically the yield earned in stETH. This contract works in tandem with Arbitrum Bridge to securely receive cross-chain token bridged assets. Once received, these assets (typically wstETH) can be swapped or utilized within the L2 environment—for example, converted into MOR tokens and added to liquidity pools like Uniswap to support the protocol’s token economy. It serves as a bridge landing point for real yield, enabling efficient liquidity flow into the L2 network.

## Libs

### [LinearDistributionIntervalDecrease](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/libs/lineardistributionintervaldecrease)

This library manages the linear emission *decay* mechanism used to gradually reduce the amount of tokens distributed over time. It defines how the available reward amount decreases with each interval (e.g., daily, weekly), allowing the protocol to implement a predictable emission schedule. Used by the DistributionV5 contract to calculate how many MOR tokens can currently be distributed based on the time elapsed since the start of the distribution schedule.

### [LockMultiplierMath](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/libs/lockmultipliermath)

This library provides logic to compute  multipliers based on how long a user locks their staked tokens (stETH). The longer the lock duration, the higher the multiplier — encouraging users to stake for longer periods and reinforcing long-term alignment with the protocol.

### [LogExpMath](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/libs/logexpmath)

Provides high-precision mathematical functions for logarithmic and exponential operations, which are crucial in many DeFi reward calculations (e.g., bonding curves, APY adjustments, dynamic pricing). Solidity lacks native high-precision log/exp functions, so this library ensures safe and accurate computations.

### [ReferrerLib](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/libs/referrerlib)

Implements referral program logic, enabling the protocol to reward stakers for inviting others. It tracks referral relationships, determines the eligibility of rewards.

## Periphery

### **Uniswap V3**&#x20;

Used to manage MOR token liquidity on Arbitrum. These contracts allow the protocol to add/remove liquidity, perform swaps, and rebalance pools efficiently.

Used contracts:

* `SwapRouter` - facilitates MOR/ETH or MOR/stETH token swaps (and vice versa) within the Uniswap V3 ecosystem.
* `NonfungiblePositionManager` - manages liquidity positions represented as NFTs in Uniswap V3.

Links:

* <https://docs.uniswap.org/contracts/v3/overview>
* <https://docs.uniswap.org/contracts/v3/reference/deployments/ethereum-deployments>

### Layer Zero V1

Cross-chain messaging protocol used to connect Ethereum (L1) and Arbitrum (L2).

Used contracts:

* `EndpointV1` - acts as the primary messaging interface between L1 and L2.

Links:

* <https://docs.layerzero.network/v1/developers/evm/evm-guides/getting-started>
* <https://docs.layerzero.network/v1/deployments/deployed-contracts?chains=arbitrum%2Cethereum>

### Arbitrum Bridge

Used to transfer native or ERC-20 tokens between Ethereum and Arbitrum.

Used contracts:

* `L1GatewayRouter`  - sends token bridging instructions from Ethereum.
* `L2GatewayRouter` - receives tokens on Arbitrum and finalizes transfer.

Links:

* <https://docs.arbitrum.io/welcome/get-started>
* <https://docs.arbitrum.io/build-decentralized-apps/reference/contract-addresses>

### ChainLink

Used to fetch reliable and up-to-date price feeds for each supported staking token.

Used contracts:

* `EACAggregatorProxy` - the contract uses to receive latest price feeds.

Links:

* [https://docs.chain.link/data-feeds/price-feeds/addresses](https://docs.chain.link/data-feeds/price-feeds/addresses?network=ethereum\&page=1\&testnetPage=1)

### Aave

Used to generate yield from stakes deposited into the `DepositPool`s.

Used contracts:

* `Pool` - the primary contract responsible for handling deposits, withdrawals, borrowing, repayments, and liquidation actions within the Aave protocol. It manages liquidity pools, calculates interest, and maintains reserves.
* `AaveProtocolDataProvider` - a utility contract providing comprehensive data about reserve tokens, user positions, and protocol metrics. It enables fetching reserve configurations, token addresses, user account data, current borrowing/deposit rates, and other vital information from the protocol.

Links:

* <https://aave.com/docs/resources/addresses>

### OpenZeppelin

Used extensively across contracts to support secure access control and upgradeability:

* `OwnableUpgradeable` – enables ownership access control.
* `UUPSUpgradeable` – facilitates contract upgradeability via the UUPS (Universal Upgradeable Proxy Standard) pattern.

Links:

* <https://docs.openzeppelin.com/contracts/4.x/access-control>
* <https://docs.openzeppelin.com/contracts/4.x/api/proxy>


# DepositPool

## Introduction

The `DepositPool` contract serves as the primary staking and reward tracking layer in the protocol. It manages user deposits of a specific ERC20 token, tracks staking positions and lock periods, handles reward rate logic, and provides mechanisms for secure and modular reward claiming — including support for referrers and delegated claims. This contract operates as a satellite to the central `Distributor` and `RewardPool` contracts, and can be deployed per reward pool on Ethereum.

### Key Responsibilities

1. Staking and Withdrawal Logic
   * Accepts ERC20 deposits from users into specific reward pools.
   * Supports both public and private reward pools (public allow permissionless staking; private are managed by the owner).
   * Enables staking with custom lock periods and optional referrer assignment.
   * Allows secure withdrawal with respect to lock rules and minimum stake constraints.
2. Reward Calculation Integration
   * Interfaces with the `RewardPool` contract to validate pool configurations (e.g., public/private).
   * Works with the `Distributor` to request reward updates before any user action.
   * Computes a “virtual deposit” value factoring in lock duration and referral tiers.
   * Uses internal logic to calculate each user’s current pending rewards and referrer yield.
3. Claim and Delegation System
   * Supports direct reward claiming by stakers.
   * Enables delegated reward claiming via `claimSender` and `claimReceiver` mappings.
   * Supports separate claiming of referrer rewards.
   * Ensures secure access control on all delegated operations.
4. Cross-Contract Coordination
   * Verifies pool status from the `RewardPool` contract.
   * Uses the `Distributor` to distribute rewards and transfer yield tokens as needed.
   * Relies on shared PRECISION constants and math utilities from `LockMultiplierMath` and `ReferrerLib`.

## Storage

### isNotUpgradeable

Returns `true` if the contract no longer supports upgrades to a new version.

```solidity
bool public isNotUpgradeable;
```

### depositToken

The stETH token address, see the LIDO [doc](https://docs.lido.fi/deployed-contracts/).

```solidity
address public depositToken;
```

### rewardPoolsData

Contain additional internal information about MOR reward pools for buckets. `poolsData[<poolId>]`.

```solidity
mapping(uint256 => RewardPoolData) public rewardPoolsData;

struct RewardPoolData {
  uint128 lastUpdate;
  uint256 rate;
  uint256 totalVirtualDeposited;
}
```

| Name                    | Description                                                           |
| ----------------------- | --------------------------------------------------------------------- |
| `lastUpdate`            | The unix epoch timestamp in seconds when the rate was updated.        |
| `rate`                  | The current pool coefficient, used to calculate awards.               |
| `totalVirtualDeposited` | The total amount of stETH deposited in the pool with multiplier, wei. |

### usersData

Stores all staking-related data for users.  `usersData[<stakerAddress>][<poolId>].`

```solidity
mapping(address => mapping(uint256 => UserData)) public usersData;

struct UserData {
  uint128 lastStake;
  uint256 deposited;
  uint256 rate;
  uint256 pendingRewards;
  uint128 claimLockStart;
  uint128 claimLockEnd;
  uint256 virtualDeposited;
  uint128 lastClaim;
  address referrer;
}
```

| Name               | Description                                                                                                                                                |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `lastStake`        | The unix epoch timestamp in seconds when the user stake was last.                                                                                          |
| `deposited`        | The amount of staked stETH, wei.                                                                                                                           |
| `rate`             | The last user reward rate, used to calculate awards.                                                                                                       |
| `pendingRewards`   | The last saved MOR rewards for the user. This value is updated when stake, withdraw or claim from the user account occurs. It is not the final award. Wei. |
| `claimLockStart`   | MOR rewards lock period starts at this timestamp. Seconds.                                                                                                 |
| `claimLockEnd`     | MOR rewards lock period end at this timestamp. Seconds.                                                                                                    |
| `virtualDeposited` | The amount of staked stETH, with multipliers. Wei.                                                                                                         |
| `lastClaim`        | The last claim timestamp in seconds.                                                                                                                       |
| `referrer`         | The referrer address.                                                                                                                                      |

### totalDepositedInPublicPools

Tracks the total amount of stETH deposited in the public pools (specifically the capital bucket). Wei.

### referrerTiers

Stores referral reward tiers per pool. `referrerTiers[<poolId>][<tierIndex>]`.

```solidity
mapping(uint256 => ReferrerTier[]) public referrerTiers;

struct ReferrerTier {
  uint256 amount;
  uint256 multiplier;
}
```

| Name         | Description                                                      |
| ------------ | ---------------------------------------------------------------- |
| `amount`     | The minimal token amount for the tier, wei.                      |
| `multiplier` | The multiplier for the tier, where 1% = 0.01 \* 10<sup>25</sup>. |

### referrersData

Tracks referral activity per user and pool. `referrersData[<stakerAddress>][<poolId>]`.

```solidity
mapping(address => mapping(uint256 => ReferrerData)) public referrersData;

struct ReferrerData {
  uint256 amountStaked;
  uint256 virtualAmountStaked;
  uint256 rate;
  uint256 pendingRewards;
  uint128 lastClaim;
}
```

| Name                  | Description                                                                   |
| --------------------- | ----------------------------------------------------------------------------- |
| `amountStaked`        | The amount of referred stETH, wei.                                            |
| `virtualAmountStaked` | The amount of referred stETH, with multipliers, wei.                          |
| `rate`                | The last referrer reward rate, used to calculate awards.                      |
| `pendingRewards`      | The last saved MOR rewards for the referrer.  It is not the final award, wei. |
| `lastClaim`           | The last claim timestamp, secodns.                                            |

### **claimSender**

Defines which addresses are allowed to claim rewards on behalf of another user in a given reward `claimSender[<rewardPoolIndex>][<caller>][<allowedSender>]`

```solidity
mapping(uint256 => mapping(address => mapping(address => bool))) public claimSender;
```

### **claimReceiver**

Defines the receiver address for a user’s rewards, enabling redirection of claims. `claimReceiver[<rewardPoolIndex>][<caller>][<l2Receiver>]`

```solidity
mapping(uint256 => mapping(address => address)) public claimReceiver;
```

### **isMigrationOver**

Indicates whether the `migrate` function called.

```solidity
 bool public isMigrationOver;
```

### distributor

The address of the `Distributor` contract.

```solidity
address public distributor;
```

### **rewardPoolsProtocolDetails**

Setup limits configuration parameters used during reward calculations and user interactions.

```solidity
mapping(uint256 => RewardPoolProtocolDetails) public rewardPoolsProtocolDetails;

struct RewardPoolProtocolDetails {
  uint128 withdrawLockPeriodAfterStake;
  uint128 claimLockPeriodAfterStake;
  uint128 claimLockPeriodAfterClaim;
  uint256 minimalStake;
  uint256 distributedRewards;
}
```

| Name                            | Description                                           |
| ------------------------------- | ----------------------------------------------------- |
| `withdrawLockPeriodAfterStake_` | Lock period for withdrawals after staking, seconds.   |
| `claimLockPeriodAfterStake_`    | Lock period for claims after staking, seconds.        |
| `claimLockPeriodAfterClaim_`    | Lock period after a claim before next claim, seconds. |
| `minimalStake_`                 | Minimum staking amount required, wei.                 |
| `distributedRewards`            | Distributed reward pool rewards, wei.                 |

## Write functions for the contract owner

### DepositPool\_init

Initializes the `DepositPool` contract with the deposit token and distributor address.

```solidity
function DepositPool_init(
  address depositToken_, 
  address distributor_
) external initializer
```

| Name            | Description                            |
| --------------- | -------------------------------------- |
| `depositToken_` | Address of the stETH token.            |
| `distributor_`  | Address of the `Distributor` contract. |

### setDistributor

Updates the `Distributor` contract address.

```solidity
function setDistributor(address value_) public onlyOwner
```

| Name     | Description                            |
| -------- | -------------------------------------- |
| `value_` | Address of the `Distributor` contract. |

### setRewardPoolProtocolDetails

Sets configuration details for a specific reward pool.

```solidity
function setRewardPoolProtocolDetails(
  uint256 rewardPoolIndex_,
  uint128 withdrawLockPeriodAfterStake_,
  uint128 claimLockPeriodAfterStake_,
  uint128 claimLockPeriodAfterClaim_,
  uint256 minimalStake_
) public onlyOwner
```

| Name                            | Description                                           |
| ------------------------------- | ----------------------------------------------------- |
| `rewardPoolIndex_`              | The reward pool ID.                                   |
| `withdrawLockPeriodAfterStake_` | Lock period for withdrawals after staking, seconds.   |
| `claimLockPeriodAfterStake_`    | Lock period for claims after staking, seconds.        |
| `claimLockPeriodAfterClaim_`    | Lock period after a claim before next claim, seconds. |
| `minimalStake_`                 | Minimum staking amount required, wei.                 |

### migrate

Transfers pending stETH yield to the `Distributor` and run `supply` logic. Used once for old `DistributionV5`.

```solidity
function migrate(uint256 rewardPoolIndex_) external onlyOwner
```

| Name               | Description                 |
| ------------------ | --------------------------- |
| `rewardPoolIndex_` | The capital reward pool ID. |

### editReferrerTiers

The function to setup tiers for the refferal system.

```solidity
function editReferrerTiers(
  uint256 rewardPoolIndex_,
  ReferrerTier[] calldata referrerTiers_
) external onlyOwner poolExists(poolId_)
```

| Name               | Description                 |
| ------------------ | --------------------------- |
| `rewardPoolIndex_` | The reward pool ID.         |
| `referrerTiers_`   | The referrer tiers structs. |

### manageUsersInPrivatePool

The function to manage users in the private pool (non capital bucket). This function specifically controls the user shares in the other buckets. Each user has its own index in the array of `users_`, additional data for that user (`amounts_`, `claimLockEnds_`, `referrers_`) should have the same index.

```solidity
function manageUsersInPrivatePool(
  uint256 rewardPoolIndex_,
  address[] calldata users_,
  uint256[] calldata amounts_,
  uint128[] calldata claimLockEnds_,
  address[] calldata referrers_
) external onlyOwner poolExists(poolId_);
```

| Name               | Description                                                                         |
| ------------------ | ----------------------------------------------------------------------------------- |
| `rewardPoolIndex_` | The reward pool ID.                                                                 |
| `users_`           | The users addresses.                                                                |
| `amounts_`         | The virtual staked amount values for `users_`.  Wei.                                |
| `claimLockEnds_`   | The claim lock end values for `users_`. Default values - `[0, 0, 0...]`. Seconds.   |
| `referrers_`       | The referrer values for `users_` .Default values - `[0х000..., 0х000..., 0х000...]` |

### removeUpgradeability

Permanently disables contract upgradeability. Only callable by owner.

```solidity
function removeUpgradeability() external onlyOwner
```

## Write functions for stakers

### setClaimSender

Enables specified addresses to claim on behalf of the sender.

```solidity
function setClaimSender(
  uint256 rewardPoolIndex_,
  address[] calldata senders_,
  bool[] calldata isAllowed_
) external
```

| Name               | Description                                   |
| ------------------ | --------------------------------------------- |
| `rewardPoolIndex_` | The reward pool ID.                           |
| `senders_`         | List of addresses allowed/disallowed.         |
| `isAllowed_`       | Boolean flags per address for allow/disallow. |

### setClaimReceiver

Sets a dedicated address to receive claims on behalf of the caller.

```solidity
function setClaimReceiver(
  uint256 rewardPoolIndex_,
  address receiver_
) external
```

| Name               | Description                 |
| ------------------ | --------------------------- |
| `rewardPoolIndex_` | The reward pool ID.         |
| `receiver_`        | Address to receive rewards. |

### stake

The stake function allows users to deposit stETH into the protocol from the Ethereum network, then the staker will get a share of the rewards.&#x20;

```solidity
stake(
  uint256 rewardPoolIndex_,
  uint256 amount_, 
  uint128 claimLockEnd_, 
  address referrer_
) external;
```

| Name               | Description                                                                                     |
| ------------------ | ----------------------------------------------------------------------------------------------- |
| `rewardPoolIndex_` | The reward pool ID.                                                                             |
| `amount_`          | The stETH amount to stake, where 1 stETH = 10<sup>18.</sup>                                     |
| `claimLockEnd_`    | The unix epoch timestamp in seconds. Use the default zero value. Secodns.                       |
| `referrer_`        | The referrer address. Use the default zero address - 0x0000000000000000000000000000000000000000 |

### withdraw

The withdraw function allows users to retrieve their staked stETH after a withdraw lock period.

```solidity
function withdraw(
  uint256 poolId_, 
  uint256 amount_
) external;
```

| Name               | Description                                                    |
| ------------------ | -------------------------------------------------------------- |
| `rewardPoolIndex_` | The reward pool ID.                                            |
| `amount_`          | The stETH amount to withdraw, where 1 stETH = 10<sup>18.</sup> |

### claim

The claim function enables stakers to receive the MOR tokens they’ve accrued.

```solidity
function claim(
  uint256 rewardPoolIndex_, 
  address receiver_
) external payable;
```

| Name               | Description                             |
| ------------------ | --------------------------------------- |
| `eth_value`        | Payable amount, value, in the ETH.      |
| `rewardPoolIndex_` | The reward pool ID.                     |
| `receiver_`        | The address who will receive MOR on L2. |

### claimFor

Claims rewards for a `staker_` on caller behalf. The caller should be whitelisted by `staker_` on `setClaimSender` call. Or `claimReceiver` should exists on `setClaimReceiver` call.

```solidity
function claimFor(
  uint256 rewardPoolIndex_,
  address staker_,
  address receiver_
) external payable
```

| Name               | Description                            |
| ------------------ | -------------------------------------- |
| `eth_value`        | Payable amount, value, in the ETH.     |
| `rewardPoolIndex_` | The reward pool ID.                    |
| `staker_`          | Address of the user being claimed for. |
| `receiver_`        | Address receiving the rewards.         |

### claimReferrerTier

The function enables referrer to receive the MOR tokens they’ve accrued.

```solidity
function claimReferrerTier(
  uint256 rewardPoolIndex_, 
  address receiver_
) external payable poolExists(poolId_);
```

| Name               | Description                             |
| ------------------ | --------------------------------------- |
| `rewardPoolIndex_` | The reward pool ID.                     |
| `receiver_`        | The address who will receive MOR on L2. |

### claimReferrerTierFor

Claims referrer-tier rewards for another referrer. The caller should be whitelisted by `referrer_` on `setClaimSender` call.

```solidity
function claimReferrerTierFor(
  uint256 rewardPoolIndex_,
  address referrer_,
  address receiver_
) external payable
```

| Name               | Description                       |
| ------------------ | --------------------------------- |
| `rewardPoolIndex_` | The reward pool ID.               |
| `referrer_`        | Referrer whose reward is claimed. |
| `receiver_`        | Address to receive reward.        |

### lockClaim

The function to lock rewards and receive claim lock multiplier (power factor). Used when a user has an active stake and wants to receive a multiplier without triggering a new staking transaction.

```solidity
function lockClaim(
  uint256 rewardPoolIndex_,
  uint128 claimLockEnd_
) external poolExists(poolId_);
```

| Name               | Description                          |
| ------------------ | ------------------------------------ |
| `rewardPoolIndex_` | The reward pool ID.                  |
| `claimLockEnd_`    | The unix epoch timestamp in seconds. |

## Read functions

### getLatestUserReward

This function calculates the total claimable MOR token rewards for a given staker within a specific bucket, based on their current stake and multipliers. Where 1 MOR = 10<sup>18</sup>.

```solidity
function getLatestUserReward(
  uint256 rewardPoolIndex_, 
  address user_
) external view returns (uint256);
```

| Name               | Description         |
| ------------------ | ------------------- |
| `rewardPoolIndex_` | The reward pool ID. |
| `user_`            | The staker address. |

### getLatestReferrerReward

This function calculates the total claimable MOR token rewards for a given referrer within a specific bucket, based on referrals and tier multipliers. Where 1 MOR = 10<sup>18</sup>.

```solidity
function getLatestReferrerReward(
  uint256 rewardPoolIndex_,
  address user_
) public view returns (uint256)
```

| Name               | Description           |
| ------------------ | --------------------- |
| `rewardPoolIndex_` | The reward pool ID.   |
| `user_`            | The referrer address. |

### getCurrentUserMultiplier

The function to calculate the power factor and referrer multiplier for the specified staker. Returns the multiplier, where x1 = 10<sup>25</sup>.

<pre class="language-solidity"><code class="lang-solidity"><strong>function getCurrentUserMultiplier(
</strong>  uint256 rewardPoolIndex_, 
  address user_
) public view returns (uint256)
</code></pre>

| Name               | Description         |
| ------------------ | ------------------- |
| `rewardPoolIndex_` | The reward pool ID. |
| `user_`            | The staker address. |

### getReferrerMultiplier

The function to calculate the tier multiplier for the specified referrer. Returns the multiplier, where x1 = 10<sup>25</sup>.

```solidity
function getReferrerMultiplier(
  uint256 rewardPoolIndex_,
  address referrer_
) public view returns (uint256)
```

| Name               | Description           |
| ------------------ | --------------------- |
| `rewardPoolIndex_` | The reward pool ID.   |
| `referrer_`        | The referrer address. |

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IChainLinkDataConsumer`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```

### version

Returns the current version of the contract.

```solidity
function version() external pure returns (uint256
```


# Distributor

v1 and v2

## Introduction

The `Distributor` contract acts as the central coordination layer for distributing rewards to `DepositPool` instances across various reward pools. It is responsible for aggregating yield across strategies, calculating proportional rewards, managing price feeds via Chainlink, and forwarding yield to the L1 bridge contract for minting rewards on L2. This contract ensures that yield-based reward emissions are fairly and accurately routed according to pool performance.

### Key Responsibilities

1. Reward Aggregation and Distribution
   * Coordinates reward distribution across multiple `DepositPool` instances per `rewardPoolIndex`.
   * Aggregates token yield (e.g., from AAVE strategies) and calculates share per `DepositPool`.
   * Tracks last reward calculation time and ensures time-based emission updates.
2. `DepositPool` Registry Management
   * Supports adding deposit pools to a reward pool, with specific strategy (AAVE or NO\_YIELD...).
   * Ensures compatibility with registered reward pools via `RewardPool` contract validation.
   * Maintains mappings of pool configuration and yield tracking.
   * Automatically updates Chainlink token prices during reward distribution.
3. Chainlink Price Feed Integration
   * Uses a `ChainLinkDataConsumer` to fetch and store up-to-date prices for staked tokens.
   * Ensures rewards are calculated in terms of value (`price * yield`), not just raw token amounts.
4. Cross-Chain Yield and Reward Handling
   * Interfaces with `L1SenderV2` to send messages for reward minting on L2.
   * Enables yield withdrawal to the L1 bridge.
   * Can transfer undistributed rewards in edge cases (e.g., zero yield scenario).

## Storage

### depositPools

Maps reward pool index and deposit pool address to the deposit pool configuration. `depositPools[<rewardPoolIndex]][<DepositPool>]`.

```solidity
mapping(uint256 => mapping(address => DepositPool)) public depositPools
struct DepositPool {
  address token;
  string chainLinkPath;
  uint256 tokenPrice;
  uint256 deposited;
  uint256 lastUnderlyingBalance;
  Strategy strategy;
  address aToken;
  bool isExist;
}

/**
 * @notice The Yield strategy.
 * NONE - for tokens without yield strategy (stETH).
 * NO_YIELD - for virtual tokens in the private buckets.
 * AAVE - fot tokens with Aave yield strategy.
 */
enum Strategy {
  NONE,
  NO_YIELD,
  AAVE
}
```

| Name                    | Description                                                              |
| ----------------------- | ------------------------------------------------------------------------ |
| `token`                 | The yield token (stETH, wBTC...).                                        |
| `chainLinkPath`         | The path from the `ChainLinkDataConsumer`.                               |
| `tokenPrice`            | The last calculated token price. Used for internal calculations. Wei.    |
| `deposited`             | The deposited `token` amount. Wei.                                       |
| `lastUnderlyingBalance` | The last calculated balance that include the `yield`. Wei.               |
| `strategy`              | The `Strategy`.                                                          |
| `aToken`                | The `aToken` address for the pools with `AAVE` strategy. Zero for other. |
| `isExist`               | The existed flag. Should be true id deposit pool added.                  |

### isDepositTokenAdded

Return `true` when `DepositPool` address added to this contract.

```solidity
mapping(address => bool) public isDepositTokenAdded;
```

### distributedRewards

Tracks how much MOR reward has been distributed to each `DepositPool`. Wei. `distributedRewards[<rewardPoolIndex]][<DepositPool>]`.

```solidity
mapping(uint256 => mapping(address => uint256)) public distributedReward;
```

### depositPoolAddresses

Stores all deposit pool addresses registered for a given reward pool.

```solidity
mapping(uint256 => address[]) public depositPoolAddresses;
```

### rewardPoolLastCalculatedTimestamp

Timestamp in seconds of last reward distribution for each reward pool.

```solidity
mapping(uint256 => uint128) public rewardPoolLastCalculatedTimestamp;
```

### isPrivateDepositPoolAdded

Flags whether a private deposit pool has been added for the given reward pool index.

```solidity
mapping(uint256 => bool) public isPrivateDepositPoolAdded
```

### chainLinkDataConsumer

Address of the `ChainLinkDataConsumer` contract.

```solidity
address public chainLinkDataConsumer
```

### rewardPool

Address of the `RewardPool` contract used for reward emission logic.

```solidity
address public rewardPool
```

### l1Sender

Address of the `L1SenderV2` contract responsible for bridging rewards.

```solidity
address public l1Sender
```

### aavePoolAddressesProvider

Address of the Aave `PoolAddressesProvider` used for yield generation.

```solidity
address public aavePoolAddressesProvider
```

### aavePoolDataProvider

Address of the Aave `PoolDataProvider`.

```solidity
address public aavePoolDataProvider
```

### aaveRewardsController

Address of the Aave `RewardControler`.

```solidity
address public aaveRewardsController;
```

### undistributedRewards

Accumulated rewards not yet distributed due to zero yield.

```solidity
uint256 public undistributedRewards
```

### minRewardsDistributePeriod

Minimum delay in seconds between reward distributions in a reward pool.

```solidity
uint256 public minRewardsDistributePeriod
```

## Write functions for the contract owner

### Distributor\_init

Initializes the `Distributor` contract with addresses of key protocol dependencies.

```solidity
function Distributor_init(
    address chainLinkDataConsumer_,
    address aavePoolAddressesProvider_,
    address aavePoolDataProvider_,
    address rewardPool_,
    address l1Sender_
) external initializer
```

| Name                         | Description                                                                       |
| ---------------------------- | --------------------------------------------------------------------------------- |
| `chainLinkDataConsumer_`     | Address of the `ChainLinkDataConsumer`  contract.                                 |
| `aavePoolAddressesProvider_` | Address of Aave `PoolAddressProvider` used for detecting the Aave `Pool` address. |
| `aavePoolDataProvider_`      | Aave protocol data provider address.                                              |
| `rewardPool_`                | Address of the `RewardPool` contract.                                             |
| `l1Sender_`                  | Address of the `L1SenderV2` for cross-chain messaging.                            |

### setChainLinkDataConsumer

Sets the `ChainLinkDataConsumer` contract address.

```solidity
function setChainLinkDataConsumer(address value_) public onlyOwner
```

| Name     | Description                              |
| -------- | ---------------------------------------- |
| `value_` | Address of the `ChainLinkDataConsumer` . |

### setL1Sender

Sets the `L1SenderV2` contract.

```solidity
function setL1Sender(address value_) public onlyOwner
```

| Name     | Description                           |
| -------- | ------------------------------------- |
| `value_` | Address of the `L1SenderV2` contract. |

### setAavePoolAddressesProvider

Sets the address of the Aave `PoolAddressProvider`.

```solidity
function setAavePoolAddressesProvider(address value_) public onlyOwner
```

| Name     | Description                 |
| -------- | --------------------------- |
| `value_` | Aave pool contract address. |

### setAavePoolDataProvider

Sets the `AaveProtocolDataProvider` contract address.

```solidity
function setAavePoolDataProvider(address value_) public onlyOwner
```

| Name     | Description                               |
| -------- | ----------------------------------------- |
| `value_` | Aave pool data provider contract address. |

### setAaveRewardsController

Sets the `AaveRewardsController` contract address.

```solidity
function setAaveRewardsController(address value_) public onlyOwner
```

### setRewardPool

Sets the address of the `RewardPool` contract.

```solidity
function setRewardPool(address value_) public onlyOwner
```

| Name     | Description                          |
| -------- | ------------------------------------ |
| `value_` | Address of the reward pool contract. |

### setMinRewardsDistributePeriod

Updates the minimum time delay between reward distributions in secodns.

```solidity
function setMinRewardsDistributePeriod(uint256 value_) public onlyOwner
```

| Name     | Description                                 |
| -------- | ------------------------------------------- |
| `value_` | Minimum reward distribution delay. Seconds. |

### setRewardPoolLastCalculatedTimestamp

Sets the last reward calculation timestamp for a reward pool.

```solidity
function setRewardPoolLastCalculatedTimestamp(
  uint256 rewardPoolIndex_, 
  uint128 value_
) public onlyOwner
```

| Name               | Description                                               |
| ------------------ | --------------------------------------------------------- |
| `rewardPoolIndex_` | Index of the reward pool.                                 |
| `value_`           | Timestamp to set as last calculated timestamp in seconds. |

### addDepositPool

Registers a new deposit pool associated with a specific reward pool. Only callable by the contract owner.

```solidity
function addDepositPool(
  uint256 rewardPoolIndex_,
  address depositPoolAddress_,
  address token_,
  string memory chainLinkPath_,
  Strategy strategy_
) external onlyOwner
```

| Name                  | Description                                                  |
| --------------------- | ------------------------------------------------------------ |
| `rewardPoolIndex_`    | Index of the reward pool to associate with the deposit pool. |
| `depositPoolAddress_` | Address of the deposit pool contract.                        |
| `token_`              | Address of the ERC20 token used in the deposit pool.         |
| `chainLinkPath_`      | Path for Chainlink price feed used to determine token price. |
| `strategy_`           | Strategy for yield generation (e.g., AAVE, NONE, NO\_YIELD). |

### updateDepositTokensPrices

Updates the price data for all tokens in deposit pools associated with the given reward pool.

```solidity
function updateDepositTokensPrices(uint256 rewardPoolIndex_) public
```

| Name               | Description                                                |
| ------------------ | ---------------------------------------------------------- |
| `rewardPoolIndex_` | Index of the reward pool whose token prices need updating. |

### withdrawUndistributedRewards

Transfers undistributed MOR rewards to the `L1SenderV2` for final distribution. Callable by owner.

```solidity
function withdrawUndistributedRewards(
  address user_, 
  address refundTo_
) external payable onlyOwner
```

| Name        | Description                                  |
| ----------- | -------------------------------------------- |
| `user_`     | Address of the recipient.                    |
| `refundTo_` | Address to refund gas in case of LZ failure. |

## Write functions

### distributeRewards

Distribute latest MOR rewards to the `DepositPools`.

```solidity
function distributeRewards(uint256 rewardPoolIndex_) public
```

| Name               | Description               |
| ------------------ | ------------------------- |
| `rewardPoolIndex_` | Index of the reward pool. |

### withdrawYield

Transfers accumulated yield to the `L1SenderV2` contract.

```solidity
function withdrawYield(
  uint256 rewardPoolIndex_,
  address depositPoolAddress_
) external
```

| Name                  | Description                                        |
| --------------------- | -------------------------------------------------- |
| `rewardPoolIndex_`    | Index of the reward pool.                          |
| `depositPoolAddress_` | Address of the deposit pool withdrawing the yield. |

### claimAaveRewards

Claims Morpheus rewards from Aave protocol for the specified deposit assets. Return claimed amount.

```solidity
function claimAaveRewards(
  address[] calldata assets_,
  uint256 amount_,
  address to_,
  address reward_
) external onlyOwner returns (uint256 claimedAmount_)
```

| Name      | Description                                                           |
| --------- | --------------------------------------------------------------------- |
| `assets_` | Array of aToken addresses to claim rewards for.                       |
| `amount_` | Amount of rewards to claim (use type(uint256).max for all available). |
| `to_`     | Address that will receive the rewards.                                |
| `reward_` | Address of the reward token.                                          |

## Write functions for the DepositPool contract&#x20;

### supply

Allows a `DepositPool` to supply tokens and participate in yield generation. Return deposited amount.

```solidity
function supply(
  uint256 rewardPoolIndex_,
  address holder_,
  uint256 amount_
) external returns (uint256)
```

| Name               | Description                          |
| ------------------ | ------------------------------------ |
| `rewardPoolIndex_` | Index of the associated reward pool. |
| `holder_`          | The token holder (staker) address.   |
| `amount_`          | Amount of tokens to supply. Wei.     |

### withdraw

Allows a `DepositPool` to withdraw tokens previously deposited. Return the withdrawn amount.

```solidity
function withdraw(
  uint256 rewardPoolIndex_, 
  address receiver_,
  uint256 amount_
) external returns (uint256)
```

| Name               | Description                          |
| ------------------ | ------------------------------------ |
| `rewardPoolIndex_` | Index of the associated reward pool. |
| `receiver_`        | The token receiver address.          |
| `amount_`          | Amount of tokens to withdraw. Wei.   |

### sendMintMessage

Sends a mint message to the `L1SenderV2` for reward minting.

```solidity
function sendMintMessage(
    uint256 rewardPoolIndex_,
    address user_,
    uint256 amount_,
    address refundTo_
) external payable
```

| Name               | Description                             |
| ------------------ | --------------------------------------- |
| `rewardPoolIndex_` | Index of the reward pool.               |
| `user_`            | Address of the user to mint tokens for. |
| `amount_`          | Amount of rewards to mint. Wei.         |
| `refundTo_`        | Refund address for LayerZero.           |

## Read functions

### getDistributedRewards

Returns the amount of rewards already distributed to a deposit pool.

```solidity
function getDistributedRewards(
    uint256 rewardPoolIndex_,
    address depositPoolAddress_
) external view returns (uint256)
```

| Name                  | Description                  |
| --------------------- | ---------------------------- |
| `rewardPoolIndex_`    | Index of the reward pool.    |
| `depositPoolAddress_` | Address of the deposit pool. |

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IDistributor`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```

### version

Returns the current version of the contract.

```solidity
function version() external pure returns (uint256)
```


# v2 Distributor

Changelog

## **Reasons for changes**

The Aave protocol, when calling `supply()`, may return a smaller amount of `aToken` than was deposited. This leads to the fact that the `lastUnderlyingBalance` is less than the `deposited` amount. This is unexpected behavior that causes an error in the `Distributor` contract code during staking, withdrawal, or claiming operations. An example of such a transaction will be provided below.

Transaction - [here](https://etherscan.io/tx/0xf14e2d9def4683f8b4eddc26be0de86b3931055d85d3746d43db038b4cfd68bb).

Location of error, `Distributor.sol -> _withdrawYield()` :

```solidity
 uint256 yield_ = depositPool.lastUnderlyingBalance - depositPool.deposited;
```

## **Yield**

Yield is calculated based on the amount of `aToken`, which may be a **few wei higher or lower** than the amount of tokens deposited. This leads to minimal inaccuracies in yield calculation, which is acceptable.&#x20;

{% hint style="info" %}
In practice, this means that if a user stake, for example, 100 USDC, the contract may receive 100.1 aUSDC. The yield will be calculated as 0.1 aUSDC and will not be available to the user immediately. This means that if the user stakes and then immediately tries to withdraw the deposited tokens, they may encounter an error on the smart contract, because 100 aUSDC will not be exactly equal to 100 USDC. The solution is to wait a few minutes for the yield from the Aave protocol to be accrued. **This will only occur if the user is the last staker and attempts to withdraw all of their tokens after the stake.**
{% endhint %}

## **Solution**

It is necessary to track the `aToken` balance independently from the deposit token, separating the `amount_` specified during deposit and withdrawal, and the one recorded in `underlyingAmount_`.

Pull request: <https://github.com/MorpheusAIs/SmartContracts/pull/60>.

## Consequences

We do not see any critical consequences from this issue. Only one deposit pool (wBTC) was affected and is currently unable to operate due to the error described above. Other deposit pools are functioning since the amount of `aToken` is greater than the deposited amount, which does not violate the contract logic. After the update, the `distributeRewards()` function will overwrite the `lastUnderlyingBalance` variable to the most recent value.

## Code changelog

#### supply()

A calculation of the actual amount of `aToken` received by the `Distributor` contract has been added to the `supply()` function. Thus, in the case of the Aave pool, we will add the actual `aTokens` received to the last calculated balance. The deposit token is deducted in the amount specified by the user (without changes). For stETH, the `underlyingAmount_` variable is set equal to the deposit amount (without changes).

```solidity
function supply(
  uint256 rewardPoolIndex_, 
  address holder_, 
  uint256 amount_
) external returns (uint256) {
  ...

  uint256 underlyingAmount_ = amount_;
  if (depositPool.strategy == Strategy.AAVE) {
    ...
    uint256 underlyingTokenBalanceBefore_ = IERC20(depositPool.aToken).balanceOf(address(this));
    AaveIPool(aavePool_).supply(depositPool.token, amount_, address(this), 0);
    uint256 underlyingTokenBalanceAfter_ = IERC20(depositPool.aToken).balanceOf(address(this));
    underlyingAmount_ = underlyingTokenBalanceAfter_ - underlyingTokenBalanceBefore_;
  }

  ...
  depositPool.lastUnderlyingBalance += underlyingAmount_;

  return amount_;
}

```

#### withdraw()

When withdrawing the deposit token, the exact amount check, which was previously implemented only for stETH, has now been applied to all deposit pools. This was done to improve security, as Aave declares the "exact" withdrawal amount in the return value, and it can be assumed that this amount may differ. Additionally, a calculation has been added to determine the precise amount of `aToken` spent.

```solidity
function withdraw(
  uint256 rewardPoolIndex_,
  address receiver_,
  uint256 amount_
) external returns (uint256) {
  ...
  uint256 underlyingAmount_ = amount_;

  uint256 depositTokenBalanceBefore_ = IERC20(depositPool.token).balanceOf(receiver_);
  if (depositPool.strategy == Strategy.AAVE) {
    uint256 underlyingTokenBalanceBefore_ = IERC20(depositPool.aToken).balanceOf(address(this));
    AaveIPool(AaveIPoolAddressesProvider(aavePoolAddressesProvider).getPool()).withdraw(
      depositPool.token,
      amount_,
      receiver_
    );
    uint256 underlyingTokenBalanceAfter_ = IERC20(depositPool.aToken).balanceOf(address(this));
    underlyingAmount_ = underlyingTokenBalanceBefore_ - underlyingTokenBalanceAfter_;
  } else {
    IERC20(depositPool.token).safeTransfer(receiver_, amount_);
  }
  uint256 depositTokenBalanceAfter_ = IERC20(depositPool.token).balanceOf(receiver_);
  amount_ = depositTokenBalanceAfter_ - depositTokenBalanceBefore_;

  depositPool.deposited -= amount_;
  depositPool.lastUnderlyingBalance -= underlyingAmount_;

  ...
}
```

#### \_withdrawYield()

Processing has been added to ensure that the `lastUnderlyingBalance_` amount must be greater than the `deposited_` amount.

```solidity
function _withdrawYield(
  uint256 rewardPoolIndex_, 
  address depositPoolAddress_
) private {
  ...
  uint256 lastUnderlyingBalance_ = depositPool.lastUnderlyingBalance;
  uint256 deposited_ = depositPool.deposited;
  if (lastUnderlyingBalance_ <= deposited_) {
    return;
  }

  uint256 yield_ = lastUnderlyingBalance_ - deposited_;
  if (depositPool.strategy == Strategy.AAVE) {
    uint256 underlyingTokenBalanceBefore_ = IERC20(depositPool.aToken).balanceOf(address(this));
    AaveIPool(AaveIPoolAddressesProvider(aavePoolAddressesProvider).getPool()).withdraw(
      depositPool.token,
      yield_,
      l1Sender
    );
    uint256 underlyingTokenBalanceAfter_ = IERC20(depositPool.aToken).balanceOf(address(this));
    yield_ = underlyingTokenBalanceBefore_ - underlyingTokenBalanceAfter_;
  } else {
    ...
  }
  ...
}

```

#### Other

Some internal variable names were also changed, and the version and name of the smart contract were updated (Distributor -> DistributorV2).


# ChainLinkDataConsumer

## Introduction

The `ChainLinkDataConsumer` contract is a utility component within the protocol, designed to provide real-time, reliable token price data using Chainlink’s decentralized oracle network. Its primary purpose is to normalize and convert the yield generated from different staking tokens (e.g., stETH, wBTC, cbETH) into a common base currency, such as USD. This normalization is crucial for accurately aggregating yield across various DepositPools and ensuring fair distribution of MOR rewards, regardless of the asset type contributed by users.

The contract supports the composition of multiple Chainlink feeds into a single price path (e.g., `cbETH/ETH/USD`), which allows for flexible and accurate multi-hop price resolution. These paths are referenced via unique string identifiers and stored as a hash in the contract’s mapping structure. Though the contract does not calculate MOR rewards directly, it provides the foundational price data necessary for consistent yield evaluation.

### Key Responsibilities

1. Composable price path resolution: supports multi-step Chainlink feed composition using stored feed sequences.
2. Accurate yield normalization: normalizes yield values to a unified base unit (18 decimals, typically USD), enabling consistent reward calculations.
3. Dynamic feed configuration: allows the owner to register or update Chainlink data feeds by providing token path identifiers and feed arrays.
4. Chainlink oracle integration: queries live Chainlink aggregators and computes composite price outputs with correct decimal adjustment and error handling.

## Storage

### dataFeeds

The Chainlink data feed addresses. `dataFeeds[<pathId>]`

```solidity
mapping(bytes32 => address[]) public dataFeeds;
```

### allowedPriceUpdateDelay

The maximum allowed delay in seconds for the price update between `ChainLink` data and current timestamp in seconds. Where `address` - feed, `uint64` - timestamp.

```solidity
mapping(address => uint64) public allowedPriceUpdateDelay;
```

## Write functions for the contract owner

### updateDataFeeds

Updates the list of Chainlink price feed contracts for specified paths. Only callable by the contract owner.

```solidity
function updateDataFeeds(
  string[] calldata paths_,
  address[][] calldata feeds_
) external onlyOwner
```

| Name     | Description                                                                                                       |
| -------- | ----------------------------------------------------------------------------------------------------------------- |
| `paths_` | Array of unique feed path strings (e.g., \["ETH/USD"])                                                            |
| `feeds_` | Array of feed address chains, each corresponding to a path. Can include multiple hops (e.g., \[ETH/USD, USD/DAI]) |

### setAllowedPriceUpdateDelay

The function to set the maximum delay between the returned update time and the current time. For example, if set to 120 seconds, the price returned by `ChainLink` should not be older than 120 seconds from the time of the call.

```solidity
function setAllowedPriceUpdateDelay(
  address feed_,
  uint64 allowedPriceUpdateDelay_
) external onlyOwner;
```

| Name                       | Description                                   |
| -------------------------- | --------------------------------------------- |
| `feed_`                    | The feed address from the ChainLink protocol. |
| `allowedPriceUpdateDelay_` | The seconds.                                  |

## Read functions

### getPathId

Returns a `bytes32` hash of a feed path string. Used to access stored feeds in the mapping.

```solidity
function getPathId(string memory path_) public pure returns (bytes32)
```

| Name    | Description                            |
| ------- | -------------------------------------- |
| `path_` | The string representing the feed path. |

### decimals

Returns the standard number of decimals used for price normalization. Returns `18` as standard

```solidity
function decimals() public pure returns (uint8)
```

### getChainLinkDataFeedLatestAnswer

Fetches the latest value from the Chainlink feeds assigned to a specific path ID. Handles multi-hop price feeds (e.g., ETH → USD → EUR).

```solidity
function getChainLinkDataFeedLatestAnswer(
  bytes32 pathId_
) external view returns (uint256)
```

| Name      | Description                           |
| --------- | ------------------------------------- |
| `pathId_` | The hashed identifier of a feed path. |

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IChainLinkDataConsumer`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```

### version

Returns the current version of the contract.

```solidity
function version() external pure returns (uint256)
```


# RewardPool

## Introduction

The `RewardPool` contract encapsulates the emission logic for MOR tokens across multiple reward buckets. It defines how MOR tokens are distributed over time using emission curves, serving as a shared utility that ensures controlled and sustainable token issuance within the protocol.

The contract supports multiple independent reward pools, each corresponding to a specific bucket — a category of protocol participants eligible to earn MOR rewards. These buckets include Capital, Provider, Builder, Compute, Code, and Protection.

It implements a linear interval-based emission decay model using the `LinearDistributionIntervalDecrease` library. The contract allows the protocol owner to register reward pools with distinct configurations and provides utilities to query reward amounts over time. Each reward pool has its own emission curve, with customizable payout start time, emission amount, and decay interval.

By isolating emission logic from staking and distribution, `RewardPool` enables independent upgrades and adjustments to token economics without affecting user balances or yield sources. This modular design helps ensure scalability, transparency, and long-term reward sustainability across the ecosystem.

## Storage

### rewardPools

The MOR reward pools data, where the pool #0 is a capital reward. `pool. rewardPools[<rewardPool>]`

```solidity
RewardPool[] public rewardPools;

struct RewardPool {
  uint128 payoutStart;
  uint128 decreaseInterval;
  uint256 initialReward;
  uint256 rewardDecrease;
  bool isPublic;
}
```

| Name               | Description                                                                  |
| ------------------ | ---------------------------------------------------------------------------- |
| `payoutStart`      | The unix epoch timestamp in seconds when the pool starts to pay out rewards. |
| `decreaseInterval` | The interval in seconds between reward decreases.                            |
| `initialReward`    | The initial MOR reward for the bucket. Wei.                                  |
| `rewardDecrease`   | The MOR reward decrease per `decreaseInterval`. Wei.                         |
| `isPublic`         | `true` - for Capital bucket, `false` for others.                             |

## Write functions for the contract owner

### RewardPool\_init

Initializes the contract with a list of reward pool configurations.

```solidity
function RewardPool_init(RewardPool[] calldata poolsInfo_) external initializer
```

| Name         | Description                                      |
| ------------ | ------------------------------------------------ |
| `poolsInfo_` | Array of reward pool configs to initialize with. |

### addRewardPool

Adds a new reward pool to the registry. Only callable by the contract owner.

```solidity
function addRewardPool(RewardPool calldata rewardPool_) public onlyOwner
```

| Name          | Description                                         |
| ------------- | --------------------------------------------------- |
| `rewardPool_` | Reward pool configuration with emission parameters. |

## Validation functions uses by protocol

### onlyExistedRewardPool

Reverts if the specified reward pool does not exist.

```solidity
function onlyExistedRewardPool(uint256 index_) external view
```

| Name     | Description                         |
| -------- | ----------------------------------- |
| `index_` | Index of the reward pool to verify. |

### onlyPublicRewardPool

Reverts if the specified reward pool is not public.

```solidity
function onlyPublicRewardPool(uint256 index_) external view
```

| Name     | Description                         |
| -------- | ----------------------------------- |
| `index_` | Index of the reward pool to verify. |

### onlyNotPublicRewardPool

Reverts if the specified reward pool is public.

```solidity
function onlyNotPublicRewardPool(uint256 index_) external view
```

| Name     | Description                         |
| -------- | ----------------------------------- |
| `index_` | Index of the reward pool to verify. |

## Read functions

### getPeriodRewards

Calculates the total rewards to be distributed in a given time range using the pool’s emission curve.

```solidity
function getPeriodRewards(uint256 index_, uint128 startTime_, uint128 endTime_) external view returns (uint256)
```

| Name         | Description                                             |
| ------------ | ------------------------------------------------------- |
| `index_`     | Index of the reward pool.                               |
| `startTime_` | Start of the time interval (Unix timestamp in seconds). |
| `endTime_`   | End of the time interval (Unix timestamp in seconds).   |

### isRewardPoolExist

Checks if a reward pool exists at a specific index.

```solidity
function isRewardPoolExist(uint256 index_) public view returns (bool)
```

| Name     | Description                        |
| -------- | ---------------------------------- |
| `index_` | Index of the reward pool to check. |

### isRewardPoolPublic

Checks if a reward pool is marked as public.

```solidity
function isRewardPoolPublic(uint256 index_) public view returns (bool)
```

| Name     | Description                        |
| -------- | ---------------------------------- |
| `index_` | Index of the reward pool to query. |

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IChainLinkDataConsumer`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```

### version

Returns the current version of the contract.

```solidity
function version() external pure returns (uint256)
```


# L1SenderV2

## Introduction

The `L1SenderV2` contract serves as a critical component in the cross-chain infrastructure of the protocol. Its primary responsibility is to transfer both reward data and yield assets from Ethereum (L1) to Arbitrum (L2), ensuring that users receive accurate MOR token rewards and that the protocol’s yield is available for conversion and distribution on L2.

The contract automatically receives deposit tokens from the `Distributor` contract. These tokens represent the yield generated by various `DepositPools` and may come in different ERC-20 formats depending on the underlying staking strategy. To unify these assets for bridging, the `L1SenderV2` integrates with Uniswap v3, enabling it to swap the received tokens into wstETH. Once converted, the resulting wstETH is sent through the Arbitrum Bridge to the `L2TokenReceiverV2` contract on Arbitrum, ensuring the protocol’s yield is properly transferred and made available for liquidity and reward mechanisms on L2.

### Key Responsibilities

1. Cross-chain reward messaging via LayerZero:
   * The contract communicates with the `L2MessageReceiver` on Arbitrum using LayerZero.
   * It packages the user’s reward data (including recipient address and reward amount) and sends it securely across chains.
   * This action is triggered by the `DepositPool` contract after calculating a user’s rewards.
   * On arrival to L2, the message is decoded, and MOR tokens are minted to the user.
2. Bridging stETH yield via Arbitrum Bridge:
   * The contract manages the bridging of yield generated from stETH held by the Morpheus protocol.
   * It wraps stETH into wstETH and uses Arbitrum Bridge to transfer tokens to the `L2TokenReceiver` contract.
3. Token configuration management:
   * The contract stores configuration data for both deposit and reward tokens:
     * Deposit token: the wrapped stETH token to be bridged.
     * Reward token: LayerZero configuration for sending mint instructions.
   * It handles dynamic updates to these configurations, allowing the protocol to change tokens or gateways without redeploying the contract.
4. Automated deposit handling:

   Receives various yield tokens directly from the `Distributor` contract.
5. Uniswap V3 integration for token conversion:

   Swaps received tokens into wstETH before bridging to L2.

## Storage

### stETH

The address of the original deposit token (e.g., stETH) before it is wrapped for cross-chain transfer.

```solidity
address public stETH;
```

### distributor

The address of the `Distributor` contract.

```solidity
address public distributor;
```

### arbitrumBridgeConfig

Configuration details for bridging the stETH token via Arbitrum Bridge.

```solidity
ArbitrumBridgeConfig public arbitrumBridgeConfig;

struct ArbitrumBridgeConfig {
  address token;
  address gateway;
  address receiver;
}
```

| Name       | Description                                       |
| ---------- | ------------------------------------------------- |
| `token`    | The address of wstETH.                            |
| `gateway`  | The address of token's gateway, `L1GatewayRouter` |
| `receiver` | The `L2MessageReceiver` address.                  |

### layerZeroConfig

Configuration for the LayerZero cross-chain messaging.

```solidity
LayerZeroConfig public layerZeroConfig;

struct LayerZeroConfig {
  address gateway;
  address receiver;
  uint16 receiverChainId;
  address zroPaymentAddress;
  bytes adapterParams;
}
```

| Name                | Description                                                        |
| ------------------- | ------------------------------------------------------------------ |
| `gateway`           | The LayerZero `EnpointV1` address.                                 |
| `receiver`          | The `L2MessageReceiver` address.                                   |
| `receiverChainId`   | The receiver chain ID, from the LZ doc.                            |
| `zroPaymentAddress` | The LayerZero ZRO payment address for gas fees.                    |
| `adapterParams`     | LayerZero adapter parameters used to customize messaging behavior. |

## Write functions for the contract owner

### L1SenderV2\_\_init

Initializes the contract. This is a one-time setup function, used during deployment via proxies.

```solidity
function L1SenderV2__init() external initializer
```

### setStETh

Allows the contract owner to set or update the address of the stETH token.

```solidity
function setStETh(address value_) external onlyOwner
```

| Name     | Description             |
| -------- | ----------------------- |
| `value_` | The stETH token address |

### setDistributor

Allows the contract owner to set or update the address of the `Distributor` contract.

```solidity
function setDistributor(address value_) public onlyOwner
```

| Name     | Description                        |
| -------- | ---------------------------------- |
| `value_` | The `Distributor` contract address |

### setUniswapSwapRouter

Allows the contract owner to set the Uniswap v3 `SwapRouter` contract address.

```solidity
function setUniswapSwapRouter(address value_) external onlyOwner
```

| Name     | Description                       |
| -------- | --------------------------------- |
| `value_` | The `SwapRouter` contract address |

### setLayerZeroConfig

Allows the contract owner to update the LayerZero MOR token configuration used for cross-chain messaging.

```solidity
function setLayerZeroConfig(
  LayerZeroConfig calldata layerZeroConfig_
) external onlyOwner
```

| Name               | Description                                            |
| ------------------ | ------------------------------------------------------ |
| `layerZeroConfig_` | Configuration for the LayerZero cross-chain messaging. |

### setArbitrumBridgeConfig

Allows the contract owner to update the Arbitrum Bridge configuration.

```solidity
function setArbitrumBridgeConfig(
  ArbitrumBridgeConfig calldata newConfig_
) external onlyOwner
```

| Name         | Description                                         |
| ------------ | --------------------------------------------------- |
| `newConfig_` | Configuration details for bridging the stETH token. |

### sendWstETH

Transfers tokens on the contract balance (e.g., stETH and wstETH) from L1 to L2 using the Arbitrum Bridge.

```solidity
function sendWstETH(
  uint256 gasLimit_,
  uint256 maxFeePerGas_,
  uint256 maxSubmissionCost_
) external payable onlyOwner returns (bytes memory)
```

| Name                 | Description                                    |
| -------------------- | ---------------------------------------------- |
| `eth_value`          | Payable amount, value, in the ETH.             |
| `gasLimit_`          | Gas limit for the L2 execution.                |
| `maxFeePerGas_`      | Max fee for L2 execution.                      |
| `maxSubmissionCost_` | Base submission cost for the retryable ticket. |

### swapExactInputMultihop

Allows the contract owner to swap deposit asset to the wstETH via Uniswap v3. Support multihop swaps (e.g. USDC/wETH, wETH/wstETH).

```solidity
function swapExactInputMultihop(
  address[] calldata tokens_,
  uint24[] calldata poolsFee_,
  uint256 amountIn_,
  uint256 amountOutMinimum_,
  uint256 deadline_
) external onlyOwner returns (uint256)
```

| Name                | Description                                                                                      |
| ------------------- | ------------------------------------------------------------------------------------------------ |
| `tokens_`           | Tokens addresses. \[USDC, wETH, wstETH]                                                          |
| `poolsFee_`         | Uniswap v3 pool fee (e.g., 3000 = 0.3%).                                                         |
| `amountIn_`         | The input token amount to swap. See the token decimals for the precision.                        |
| `amountOutMinimum_` | The minimal tokens amount at the end of swap (wstETH). See the token decimals for the precision. |
| `deadline_`         | Expiry timestamp in seconds for the transaction.                                                 |

#### Explanation

Uniswap UI can be used to detect the best route. With the help of this, it is possible to form all TX params exept `deadline_`&#x20;

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

For example, we want to swap `wstETH->tBTC` (in real practice, you will do the swap in reverse `USDC->wstETH`, `wBTC->wstETH`...; this screenshot is for illustrative purposes only.

* `tokens_`: look at the order routing on the UI, `[wstETH, wETH, tBTC]`.
* `poolsFee_`: look at the percent near the pool icons, `[100, 2000]`. It is equals to `[0.01%, 0.2%]`.
* `amountIn_`: amount to swap, `0.00040790..`. wstETH, `407900000000000` wei in token decimals.
* `amountOutMinimum_`: amount to receive, `0.0000181086` tBTC, `18108600000000` wei in token decimals. You can decrease this value on 1-3%.
* `deadline_`: TX execution timestamp in seconds + 1 or 2 minutes.

## Write functions for the Distributor contract

### sendMintMessage

Sends a cross-chain message via LayerZero to L2, instructing minting of MOR tokens to the user.

```solidity
function sendMintMessage(
  address user_, 
  uint256 amount_, 
  address refundTo_
) external payable
```

| Name        | Description                                  |
| ----------- | -------------------------------------------- |
| `user_`     | Recipient address on L2.                     |
| `amount_`   | Amount of tokens to mint. Wei.               |
| `refundTo_` | Address that receives any unspent msg.value. |

## Read functions

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IL1SenderV2`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```

### version

Returns the current version of the contract.

```solidity
function version() external pure returns (uint256)
```


# L1SenderV3

## Introduction

The `L1SenderV3` contract serves as a critical component in the cross-chain infrastructure of the protocol. Its primary responsibility is to transfer both reward data and yield assets from Ethereum (L1) to Base (L2), ensuring that users receive accurate MOR token rewards and that the protocol’s yield is available for conversion and distribution on L2.

The contract automatically receives deposit tokens from the `Distributor` contract. These tokens represent the yield generated by various `DepositPools` and may come in different ERC-20 formats depending on the underlying staking strategy. To unify these assets for bridging, the `L1SenderV3` integrates with Uniswap v3, enabling it to swap the received tokens into wstETH. Once converted, the resulting wstETH is sent through the Lido Bridge to the `L2TokenReceiverV2` contract on Arbitrum, ensuring the protocol’s yield is properly transferred and made available for liquidity and reward mechanisms on L2.

### Key Responsibilities

1. Cross-chain reward messaging via LayerZero:
   * The contract communicates with the `L2MessageReceiver` on Arbitrum using LayerZero.
   * It packages the user’s reward data (including recipient address and reward amount) and sends it securely across chains.
   * This action is triggered by the `DepositPool` contract after calculating a user’s rewards.
   * On arrival to L2, the message is decoded, and MOR tokens are minted to the user.
2. Bridging stETH yield via Lido Bridge:
   * The contract manages the bridging of yield generated from stETH held by the Morpheus protocol.
   * It wraps stETH into wstETH and uses Lido Bridge to transfer tokens to the `L2TokenReceiver` contract.
3. Token configuration management:
   * The contract stores configuration data for both deposit and reward tokens:
     * Deposit token: the wrapped stETH token to be bridged.
     * Reward token: LayerZero configuration for sending mint instructions.
   * It handles dynamic updates to these configurations, allowing the protocol to change tokens or gateways without redeploying the contract.
4. Automated deposit handling:

   Receives various yield tokens directly from the `Distributor` contract.
5. Uniswap V3 integration for token conversion:

   Swaps received tokens into wstETH before bridging to L2.

## Storage

### stETH

The address of the original deposit token (e.g., stETH) before it is wrapped for cross-chain transfer.

```solidity
address public stETH;
```

### distributor

The address of the `Distributor` contract.

```solidity
address public distributor;
```

### tokenBridgeConfig

Configuration details for bridging the stETH token via Lido Bridge.

```solidity
TokenBridgeConfig public tokenBridgeConfig;

struct TokenBridgeConfig {
  address token;
  address gateway;
  address receiver;
}
```

| Name       | Description                                       |
| ---------- | ------------------------------------------------- |
| `token`    | The address of wstETH.                            |
| `gateway`  | The address of token's gateway, `L1GatewayRouter` |
| `receiver` | The `L2MessageReceiver` address.                  |

### messageBridgeConfig

Configuration for the LayerZero cross-chain messaging.

```solidity
MessageBridgeConfig public messageBridgeConfig;

struct LayerZeroConfig {
  address gateway;
  address receiver;
  uint16 receiverChainId;
  address zroPaymentAddress;
  bytes adapterParams;
}
```

| Name                | Description                                                        |
| ------------------- | ------------------------------------------------------------------ |
| `gateway`           | The LayerZero `EnpointV1` address.                                 |
| `receiver`          | The `L2MessageReceiver` address.                                   |
| `receiverChainId`   | The receiver chain ID, from the LZ doc.                            |
| `zroPaymentAddress` | The LayerZero ZRO payment address for gas fees.                    |
| `adapterParams`     | LayerZero adapter parameters used to customize messaging behavior. |

## Write functions for the contract owner

### L1SenderV3\_\_init

Initializes the contract. This is a one-time setup function, used during deployment via proxies.

```solidity
function L1SenderV3__init() external initializer
```

### setStETh

Allows the contract owner to set or update the address of the stETH token.

```solidity
function setStETh(address value_) external onlyOwner
```

| Name     | Description             |
| -------- | ----------------------- |
| `value_` | The stETH token address |

### setDistributor

Allows the contract owner to set or update the address of the `Distributor` contract.

```solidity
function setDistributor(address value_) public onlyOwner
```

| Name     | Description                        |
| -------- | ---------------------------------- |
| `value_` | The `Distributor` contract address |

### setUniswapSwapRouter

Allows the contract owner to set the Uniswap v3 `SwapRouter` contract address.

```solidity
function setUniswapSwapRouter(address value_) external onlyOwner
```

| Name     | Description                       |
| -------- | --------------------------------- |
| `value_` | The `SwapRouter` contract address |

### setLayerZeroConfig

Allows the contract owner to update the LayerZero MOR token configuration used for cross-chain messaging.

```solidity
function setMessageBridgeConfig(
  MessageBridgeConfig calldata config_
) external onlyOwner
```

| Name      | Description                                            |
| --------- | ------------------------------------------------------ |
| `config_` | Configuration for the LayerZero cross-chain messaging. |

### setArbitrumBridgeConfig

Allows the contract owner to update the Lido Bridge configuration.

```solidity
function setTokenBridgeConfig(
  TokenBridgeConfig calldata config_
) external onlyOwner
```

| Name      | Description                                         |
| --------- | --------------------------------------------------- |
| `config_` | Configuration details for bridging the stETH token. |

### sendWstETH

Transfers tokens on the contract balance (e.g., stETH and wstETH) from L1 to L2 using the Lido Bridge.

```solidity
function sendWstETH(uint32 l2Gas_, bytes calldata data_) external onlyOwner;
```

| Name     | Description                                                                                                                                                                                           |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `l2Gas_` | Gas limit required to complete the deposit on L2.                                                                                                                                                     |
| `data_`  | Optional data to forward to L2. This data is provided solely as a convenience for external contracts. Aside from enforcing a maximum length, these contracts provide no guarantees about its content. |

### swapExactInputMultihop

Allows the contract owner to swap deposit asset to the wstETH via Uniswap v3. Support multihop swaps (e.g. USDC/wETH, wETH/wstETH).

```solidity
function swapExactInputMultihop(
  address[] calldata tokens_,
  uint24[] calldata poolsFee_,
  uint256 amountIn_,
  uint256 amountOutMinimum_,
  uint256 deadline_
) external onlyOwner returns (uint256)
```

| Name                | Description                                                                                      |
| ------------------- | ------------------------------------------------------------------------------------------------ |
| `tokens_`           | Tokens addresses. \[USDC, wETH, wstETH]                                                          |
| `poolsFee_`         | Uniswap v3 pool fee (e.g., 3000 = 0.3%).                                                         |
| `amountIn_`         | The input token amount to swap. See the token decimals for the precision.                        |
| `amountOutMinimum_` | The minimal tokens amount at the end of swap (wstETH). See the token decimals for the precision. |
| `deadline_`         | Expiry timestamp in seconds for the transaction.                                                 |

## Write functions for the Distributor contract

### sendMintMessage

Sends a cross-chain message via LayerZero to L2, instructing minting of MOR tokens to the user.

```solidity
function sendMintMessage(
  address user_, 
  uint256 amount_, 
  address refundTo_
) external payable
```

| Name                      | Description                                                                                                                                                                                                                                                                                                                                                         |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `value (sendMintMessage)` | <p>Requires a bit of native gas token so the LZ relayer can complete the message delivery on the destination chain. <br>This value can be estimated: <a href="https://docs.layerzero.network/v1/developers/evm/evm-guides/advanced/estimating-message-fees"><https://docs.layerzero.network/v1/developers/evm/evm-guides/advanced/estimating-message-fees></a>.</p> |
| `user_`                   | Recipient address on L2.                                                                                                                                                                                                                                                                                                                                            |
| `amount_`                 | Amount of MOR tokens to mint. Wei.                                                                                                                                                                                                                                                                                                                                  |
| `refundTo_`               | If the source transaction is cheaper than the amount of value passed, refund the additional amount to this address on the L1.                                                                                                                                                                                                                                       |

## Read functions

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IL1SenderV3`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```

### version

Returns the current version of the contract.

```solidity
function version() external pure returns (uint256)
```


# Changelog

v2 -> v3

## Overview

The changes in this contract are related to moving the minting of MOR tokens and migrating new liquidity from the Arbitrum network to the Base network.

This contract in v2 uses two bridges: the Arbitrum Bridge for transferring liquidity, and LayerZero for sending messages to mint tokens on L2.

Moving from Arbitrum to Base using LayerZero will not be a problem and only requires changing contract configuration. On the other hand, it is not possible to use the Arbitrum Bridge to transfer liquidity to Base. Therefore, to meet the new requirements, the bridge used for transferring liquidity must be replaced with Lido's bridge.

## Storage changes

* `arbitrumBridgeConfig` renamed to `tokenBridgeConfig`. Remove the binding to a specific bridge and make it more abstract. The function that sets these parameters has been renamed accordingly.
* `layerZeroConfig` renamed to `messageBridgeConfig`. Remove the binding to a specific bridge and make it more abstractThe function that sets these parameters has been renamed accordingly.

## Functions changes

#### setTokenBridgeConfig

We've also added handling for the case when we reconfigure from the Arbitrum bridge to the Lido bridge. The Arbitrum bridge uses a gateway via an additional call, which must be handled in new version. Lido deployments: <https://docs.lido.fi/deployed-contracts/#base>

```solidity
if (oldConfig_.wstETH != address(0)) {
  IERC20(stETH).approve(oldConfig_.wstETH, 0);

  address oldGateway_;
  try IGatewayRouter(oldConfig_.gateway).getGateway(oldConfig_.wstETH) returns (address gateway_) {
    oldGateway_ = gateway_;
  } catch {
    oldGateway_ = oldConfig_.gateway;
  }
  IERC20(oldConfig_.wstETH).approve(oldGateway_, 0);
}
```

#### sendWstETH

This function has been changed — it now works with the Lido bridge. `l2Gas_` is the gas fee for L2 and can be taken from the Lido gateway contract. `data_` is additional information for the transfer (optional field).

```solidity
function sendWstETH(
  uint32 l2Gas_, 
  bytes calldata data_
) external onlyOwner;
```

## Test enviroment

Note that in the test environment anyone can call `sendMintMessage`. The `sendWstETH` call, as before, can only be made by the contract owner. The environment is configured so that `wstETH` transfers and MOR minting work.

#### Ethereum

<table><thead><tr><th width="203.89453125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>L1SenderV3</code></td><td><kbd>0x6Fd2674E13a42E588f83Ae74e5F22a4EE24eD75A</kbd></td></tr></tbody></table>

#### Base

<table><thead><tr><th width="203.89453125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>L2MessageReceiver</code></td><td><kbd>0xB69DbF7C9aB4597D3b3BC284Cc8771D580299baD</kbd></td></tr><tr><td><code>MOR</code></td><td><kbd>0x98e3CFBdB9707dF6107Cb1A7BD03036052EAa20e</kbd></td></tr></tbody></table>


# L2MessageReceiver

## Introduction

The `L2MessageReceiver` contract is a crucial component of the protocol's cross-chain reward distribution system. It resides on the Arbitrum network (L2) and is responsible for receiving cross-chain messages from Ethereum (L1) via LayerZero. These messages contain instructions for minting MOR tokens to users who have earned rewards based on their staked stETH in L1.

The contract ensures the secure and accurate minting of MOR tokens by validating incoming messages and calling the minting logic.

### Key Responsibilities

1. LayerZero endpoint integration: listens for and receives payloads sent from the `L1Sender` contract on Ethereum.
2. Message decoding and validation: verifies the origin and decodes message payloads to extract reward details.
3. Reward Distribution: mint the MOR token for the users.

## Storage

### rewardToken

The address of the MOR token contract on Arbitrum.

```solidity
address public rewardToken;
```

### config

The LayerZero config for cross-chain message receiving.

```solidity
Config public config;

struct Config {
  address gateway;
  address sender;
  uint16 senderChainId;
}
```

| Name            | Description                                   |
| --------------- | --------------------------------------------- |
| `gateway`       | The LayerZero `EndpointV1` contract address.  |
| `sender`        | The `L1MessageSender` contract address.       |
| `senderChainId` | The Ethereum chain id fron the LayerZero doc. |

## Write functions for the contract owner

### L2MessageReceiver\_\_init

Initializes the contract during deployment (used with proxies). Can only be called once.

```solidity
function L2MessageReceiver__init() external initializer;
```

### setParams

Sets or updates the MOR token address and LayerZero message config.

```solidity
function setParams(
  address rewardToken_,
  Config calldata config_
) external onlyOwner;
```

| Name           | Description                                             |
| -------------- | ------------------------------------------------------- |
| `rewardToken_` | Address of the MOR token on Arbitrum.                   |
| `config_`      | The LayerZero config for cross-chain message receiving. |

## Write functions for the LayerZero endpoint

### lzReceive

Receives and verifies cross-chain messages from LayerZero. Only callable by the LayerZero endpoint. Delegates execution to `nonblockingLzReceive`.

```solidity
function lzReceive(
    uint16 senderChainId_,
    bytes memory senderAndReceiverAddresses_,
    uint64 nonce_,
    bytes memory payload_
) external
```

| Name                          | Description                                       |
| ----------------------------- | ------------------------------------------------- |
| `senderChainId_`              | ID of the source chain (Ethereum L1).             |
| `senderAndReceiverAddresses_` | Encoded source/destination addresses.             |
| `nonce_`                      | Unique nonce to identify the message.             |
| `payload_`                    | ABI-encoded payload: user address and MOR amount. |

### nonblockingLzReceive

Internal message handler that performs the actual minting logic. Ensures execution does not block LayerZero.

```solidity
function nonblockingLzReceive(
    uint16 senderChainId_,
    bytes memory senderAndReceiverAddresses_,
    bytes memory payload_
) public
```

| Name                          | Description                                       |
| ----------------------------- | ------------------------------------------------- |
| `senderChainId_`              | ID of the source chain (Ethereum L1).             |
| `senderAndReceiverAddresses_` | Encoded source/destination addresses.             |
| `payload_`                    | ABI-encoded payload: user address and MOR amount. |

## Write functions

### retryMessage

Allows retrying a failed cross-chain message. Can be used to recover from transient errors or gas issues.

```solidity
function retryMessage(
    uint16 senderChainId_,
    bytes memory senderAndReceiverAddresses_,
    uint64 nonce_,
    bytes memory payload_
) external
```

| Name                          | Description                               |
| ----------------------------- | ----------------------------------------- |
| `senderChainId_`              | ID of the source chain.                   |
| `senderAndReceiverAddresses_` | Encoded source/destination addresses.     |
| `nonce_`                      | Unique message identifier.                |
| `payload_`                    | Original encoded user address and amount. |


# L2TokenReceiverV2

## Introduction

The `L2TokenReceiverV2` contract is a component of the protocol deployed on Arbitrum (L2). It is responsible for receiving stETH yield sent from Ethereum (L1) via the Arbitrum Bridge. Upon receipt, the yield is stored within the contract and can later be  converted into MOR tokens to support liquidity or distribution.

### Key Responsibilities

* Bridged token receiver: handles incoming stETH/wstETH tokens from the L1Sender contract via Arbitrum Bridge.
* Uniswap v3 Integration: enables the protocol to swap tokens or increase liquidity in Uniswap v3 pools.

***

## Storage

### router

The address of Uniswap v3 `SwapRouter` used for swaps.

```solidity
address public router;
```

### nonfungiblePositionManager

The address of Uniswap v3 `NonfungiblePositionManager` used for adding liquidity and collect fees.

```solidity
address public nonfungiblePositionManager;
```

### firstSwapParams

Holds the current token swap configuration for Uniswap v3 operations. Uses for wstETH/wETH pair.

```solidity
SwapParams public firstSwapParams;

struct SwapParams {
  address tokenIn;
  address tokenOut;
  uint24 fee;
  uint160 sqrtPriceLimitX96;
}
```

| Field               | Description                                                          |
| ------------------- | -------------------------------------------------------------------- |
| `tokenIn`           | Address of the token to be swapped from (input token).               |
| `tokenOut`          | Address of the token to be swapped to (output token).                |
| `fee`               | Uniswap v3 pool fee tier in hundredths of a bip (e.g., 3000 = 0.3%). |
| `sqrtPriceLimitX96` | Optional price limit for swap.                                       |

### secondSwapParams

Holds the current token swap configuration for Uniswap v3 operations. Uses for wETH/MOR pair.

```solidity
SwapParams public secondSwapParams;
```

## Write functions for the contract owner

### L2TokenReceiver\_\_init

Initializes the contract during deployment (used with proxies). Can only be called once.

```solidity
function L2TokenReceiver__init(
    address router_,
    address nonfungiblePositionManager_,
    SwapParams memory secondSwapParams_
) external initializer
```

| Name                          | Description                                                  |
| ----------------------------- | ------------------------------------------------------------ |
| `router_`                     | Address of Uniswap v3 `SwapRouter` contract.                 |
| `nonfungiblePositionManager_` | Address of Uniswap v3 `NonfungiblePositionManager` contract. |
| `secondSwapParams_`           | Swap parameters for the Uniswap wETH/MOR pool.               |

### editParams

Allows the contract owner to update swap parameters and reapprove token allowances.

```solidity
function editParams(
  SwapParams memory newParams_,
  bool isEditFirstParams_
) external onlyOwner
```

| Parameter            | Description                                                             |
| -------------------- | ----------------------------------------------------------------------- |
| `newParams_`         | New `SwapParams` struct for the Uniswap pool.                           |
| `isEditFirstParams_` | `True` - when edit the wstETH/wETH pair. `False` for the wETH/MOR pair. |

***

### swap

Performs a token swap using Uniswap v3 router.

```solidity
function swap(
  uint256 amountIn_,
  uint256 amountOutMinimum_,
  uint256 deadline_,
  bool isUseFirstSwapParams_
) external onlyOwner returns (uint256)
```

| Parameter            | Description                                                               |
| -------------------- | ------------------------------------------------------------------------- |
| `amountIn_`          | Amount of input token to swap. See the token decimals for the precision.  |
| `amountOutMinimum_`  | Minimum expected output amount. See the token decimals for the precision. |
| `deadline_`          | Expiry timestamp in seconds for the transaction.                          |
| `isEditFirstParams_` | `True` - when use the wstETH/wETH pair. `False` for the wETH/MOR pair.    |

Returns: output token amount.

### increaseLiquidityCurrentRange

Adds liquidity to an existing Uniswap NFT position.

```solidity
function increaseLiquidityCurrentRange(
  uint256 tokenId_,
  uint256 amountAdd0_,
  uint256 amountAdd1_,
  uint256 amountMin0_,
  uint256 amountMin1_
) external onlyOwner returns (
  uint128 liquidity_,
  uint256 amount0_,
  uint256 amount1_
 )
```

| Parameter     | Description                                                           |
| ------------- | --------------------------------------------------------------------- |
| `tokenId_`    | NFT ID of the position.                                               |
| `amountAdd0_` | Desired amount for token 0. See the token decimals for the precision. |
| `amountAdd1_` | Desired amount for token 1. See the token decimals for the precision. |
| `amountMin0_` | Minimum amount of token 0. See the token decimals for the precision.  |
| `amountMin1_` | Minimum amount of token 1. See the token decimals for the precision.  |

### collectFees

Collects all available fees from a Uniswap NFT liquidity position. Returns the collected amounts of token0 and token1.

```solidity
function collectFees(
  uint256 tokenId_
) external returns (uint256 amount0_, uint256 amount1_)
```

| Parameter  | Description            |
| ---------- | ---------------------- |
| `tokenId_` | NFT ID of the position |

## Read functions

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IL2TokenReceiverV2`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```


# Libs

{% content-ref url="/pages/E4NdeWIA9E6Grt3ML67R" %}
[LinearDistributionIntervalDecrease](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/libs/lineardistributionintervaldecrease)
{% endcontent-ref %}

{% content-ref url="/pages/lKYCrIZzaTBgBvf9viHq" %}
[LockMultiplierMath](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/libs/lockmultipliermath)
{% endcontent-ref %}

{% content-ref url="/pages/XcKJz6IAGCQ4J2mzZtgu" %}
[LogExpMath](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/libs/logexpmath)
{% endcontent-ref %}

{% content-ref url="/pages/qZeMxmMmisFXSBFA5R3K" %}
[ReferrerLib](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/libs/referrerlib)
{% endcontent-ref %}


# LinearDistributionIntervalDecrease

This library manages the linear emission *decay* mechanism used to gradually reduce the amount of tokens distributed over time. It defines how the available reward amount decreases with each interval (e.g., daily, weekly), allowing the protocol to implement a predictable emission schedule. Used by the DistributionV5 contract to calculate how many MOR tokens can currently be distributed based on the time elapsed since the start of the distribution schedule.

## Read functions

### getPeriodReward

The function to calculate the MOR reward for the period.

```solidity
function getPeriodReward(
  uint256 initialAmount_,
  uint256 decreaseAmount_,
  uint128 payoutStart_,
  uint128 interval_,
  uint128 startTime_,
  uint128 endTime_
) external pure returns (uint256)
```

| Name              | Description                                                                  |
| ----------------- | ---------------------------------------------------------------------------- |
| `initialAmount_`  | The initial MOR reward for the bucket.                                       |
| `decreaseAmount_` | The MOR reward decreases on this amount for each `interval_`.                |
| `payoutStart_`    | The unix epoch timestamp in seconds when the pool starts to pay out rewards. |
| `interval_`       | The interval in seconds between reward decreases.                            |
| `startTime_`      | The unix timestamp. Start calculate rewards from this timestamp.             |
| `endTime_`        | The unix timestamp. End calculate rewards to this timestamp.                 |


# LockMultiplierMath

This library provides logic to compute  multipliers based on how long a user locks their staked tokens (stETH). The longer the lock duration, the higher the multiplier — encouraging users to stake for longer periods and reinforcing long-term alignment with the protocol.

## Read functions

### getLockPeriodMultiplier

The function to calculate the lock period multiplier (power factor).

```solidity
function getLockPeriodMultiplier(
  uint128 start_,
  uint128 end_
) external pure returns (uint256)
```

| Name     | Description                                              |
| -------- | -------------------------------------------------------- |
| `start_` | The unix timestamp. Start calculate from this timestamp. |
| `end_`   | The unix timestamp. End calculate to this timestamp.     |


# LogExpMath

Provides high-precision mathematical functions for logarithmic and exponential operations, which are crucial in many DeFi reward calculations (e.g., bonding curves, APY adjustments, dynamic pricing). Solidity lacks native high-precision log/exp functions, so this library ensures safe and accurate computations.

Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument). Exponentiation and logarithm with arbitrary bases (x^y and log\_x(y)) are implemented by conversion to natural. Exponentiation and logarithm (where the base is Euler's number).


# ReferrerLib

Implements referral program logic, enabling the protocol to reward stakers for inviting others. It tracks referral relationships, determines the eligibility of rewards.

## Constants

### REFERRAL\_MULTIPLIER

Contain the fixed referral bonus. 1%.

```solidity
uint256 constant PRECISION = 10 ** 25;
uint256 constant REFERRAL_MULTIPLIER = (PRECISION * 101) / 100; // 1% referral bonu
```

## Read functions

### getReferralMultiplier

The function to calculate the referral multiplier. Returns `REFERRAL_MULTIPLIER` for valid addresses.

```solidity
 function getReferralMultiplier(
   address referrer_
) external pure returns (uint256) 
```

| Name        | Description           |
| ----------- | --------------------- |
| `referrer_` | The referrer address. |


# Get started

This section will help you get up and running with the protocol.

You’ll learn how to perform essential actions like staking tokens, assigning a referrer, claiming rewards, and transferring liquidity to L2.

We’ll cover key functions, protocol constraints, and how to interact with contracts either directly or via the interface.

{% hint style="info" %}
This section is currently under development.&#x20;
{% endhint %}


# Stake

The [stake](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#stake) function allows users to deposit tokens (such as stETH or other `depositToken`) into the protocol in exchange for MOR token rewards. Staking is available only for public reward pools, such as the Capital pool.

When a user calls stake, the contract verifies that the reward pool exists and is public. It ensures the provided amount is greater than zero and satisfies the `minimalStake` requirement for the selected pool. If a `claimLockEnd` is provided, it must be either zero or a future timestamp. If provided, it increases the reward multiplier and updates the user’s lock duration.

The user’s `depositToken` is transferred to the `DepositPool` contract using `transferFrom`. For stETH, due to Lido rebasing, the actual amount received may be slightly less than requested. Immediately after receiving the tokens, the `DepositPool` forwards them to the `Distributor` contract using the [supply](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/distributor#supply) method.

If the `depositToken` supports external yield (e.g., Aave yield), the `Distributor` deposits them into Aave. If the token is stETH, it is not deposited and is held directly by the `Distributor`.

Reward multipliers are calculated using two components: the lock period (`claimLockEnd`) and a referrer address if one is provided. These multipliers increase the user’s virtual stake, which determines the share of rewards the user is entitled to. If the user passes their own address as referrer, the bonus still applies.

Before updating state, the contract synchronizes the reward coefficient by calling [`distributeRewards`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/distributor#distributedrewards) on the `Distributor`. This ensures the latest emission state is considered when updating the user’s reward rate.

Staking resets the withdrawal and claim lock timers. Each new stake requires the user to wait again before being able to withdraw or claim rewards, based on pool-level lock parameters.

To execute this function successfully, the user must have approved the `DepositPool` contract to spend their tokens. The staked amount must satisfy the pool’s minimum, and the `rewardPoolIndex` must correspond to a valid public pool.


# Withdraw

The [withdraw](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#withdraw) function allows users to partially or fully withdraw their previously staked tokens from a public reward pool. This operation reduces the user’s stake and, consequently, their share of MOR rewards.

Before executing a withdrawal, the contract verifies that the selected `rewardPoolIndex` corresponds to a valid and public reward pool. The withdrawal is only permitted if a required delay since the last stake (defined in the pool configuration as `withdrawLockPeriodAfterStake`) has passed.

The final withdrawn amount must also respect the `minimalStake` rule: the remaining user stake (if any) must not fall below the minimum stake required by the pool unless the user fully exits.

If the pool is public, the contract first calls `distributeRewards` to ensure the reward coefficient is up to date. Then, it calculates the user’s current rewards and applies the necessary multipliers to recalculate the virtual deposit. This ensures fair and accurate distribution of future rewards after the withdrawal. Then, the withdrawn tokens are first pulled from the `Distributor` using [withdraw](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/distributor#withdraw) and then transferred to the user via `safeTransfer`

The user may continue to interact with the contract or fully exit their stake. Fully exiting resets most of their staking data except reward history.


# Claim

The [claim](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#claim) function allows a user to claim their accumulated MOR rewards from a reward pool. This function is typically called after a lock period has expired or when the user wants to realize pending rewards. The caller claims their rewards, and the minted MOR tokens are sent to the specified receiver address on L2.

Before transferring any rewards, the contract enforces next conditions:

* The minimum claim lock period since the last stake must have passed.
* The minimum interval since the last claim must have passed.
* The custom claim lock (set via `claimLockEnd`) must have expired.

If all conditions are met, the contract calculates the latest reward amount based on the user’s virtual deposit and the difference in the reward coefficient. The claim updates the user’s multiplier.

Finally, the `sendMintMessage` function is called on the `Distributor` to initiate MOR minting to the receiver.

No deposit tokens are moved during the claim. Only MOR tokens are minted cross-chain (via LayerZero) to the user’s address on the destination chain.

## ClaimFor

The claimFor function allows another address to claim rewards on behalf of a user. This supports use cases like automated agents, wallets, or third-party services claiming on users’ behalf.

The contract verifies one of the following:

* The staker has explicitly whitelisted the `msg.sender` via `setClaimSender`.
* Or, the staker has assigned a fixed `claimReceiver` address via `setClaimReceiver`— in that case, receiver is overridden with the preconfigured address.

The rest of the logic mirrors the `claim` function.


# Referral system

## Overview

The protocol referral system is a fully on-chain mechanism designed to incentivize community-driven growth. It enables existing users (**referrers**) to invite new stakers (**referees**) to stake into the protocol and rewards both parties accordingly. This guide outlines how the system works from a technical and user interaction standpoint.

The referral system allows a user (**referrer**) to share their address with others. When a new user (**referee**) stakes with that referral address, the referee receives a 1% bonus, and the referrer can receive up to 15% in MOR tokens depending on the total amount deposited by their referees.

The system is implemented directly in the `DepositPool` contract and uses storage mappings to track referral tiers, user deposits, and accumulated rewards. `ReferrerLib` uses for the internal calculations.

## Mechanics

### Referral Address Creation

* Any wallet address can be used as a referral address. Except for the zero address — the zero address indicates that the referee is not set.
* No separate registration is required — the referrer simply provides their address to others.

### Staking with a referral

When a new user (the referee) wants to participate in staking, they use the [`stake`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#stake) function of the [`DepositPool`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool) contract. As part of this call, they provide the wallet address of the person who referred them by passing it as the `referrer_` parameter.

The contract then stores this address as the user’s associated referrer and updates internal referral data accordingly. This includes tracking the total staked amount associated with that referrer, which can impact the referrer’s bonus tier.

As an immediate benefit, the referee (staker) receives a 1% bonus on their deposit, increasing their virtual stake and potential MOR rewards.

### Referrer rewards

The referrer earns MOR rewards based on the total deposits made by referees using their referral address. The rewards are tiered based on cumulative virtual stETH deposits. Tier updates are performed automatically in `_applyReferrerTier` function.

| Tier | Total virtual stETH deposited | Bonus from referees stakes |
| ---- | ----------------------------- | -------------------------- |
| 0    | ≥ 1 stETH and < 2.5 stETH     | 3%                         |
| 1    | ≥ 2.5 stETH and < 25 stETH    | 5%                         |
| 2    | ≥ 25 stETH and < 62.5 stETH   | 10%                        |
| 3    | ≥ 62.5 stETH                  | 15%                        |

To retrieve information about referral tiers and the current tier of a user (referrer), the `DepositPool` contract provides public view functions and structured storage that can be accessed on-chain or via a blockchain indexer.

Referral tiers for a given reward pool (bucket) are stored in the [`referrerTiers`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#referrertiers) mapping, which maps a `rewardPoolIndex` to an array of `ReferrerTier` structs. Each `ReferrerTier` contains two fields:&#x20;

* Required amount of stETH deposited by referees (amount) in wei.
* Corresponding multiplier that determines the MOR bonus the referrer receives, where `<multiplier> / 10^23 = <bonusPercent>`

To determine which tier a specific user (referrer) currently belongs to, we can use [`referrersData`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#referrersdata). This struct contains a field `virtualAmountStaked` which reflects the total staked amount attributed to that referrer from all referees. By comparing this value with the thresholds defined in `referrerTiers`, you can determine the user’s active tier and associated bonus multiplier.

For convenience, the function [`getReferrerMultiplier`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#getreferrermultiplier) can be used to get the current effective multiplier for a specific referrer, accounting for their tier status.

### Lock Compatibility

Referrer rewards are not blocked by the referee’s lock conditions. This means a referrer can claim their MOR bonus even if the referee’s MOR is still locked under a Power Factor curve.

### No Referral Provided

If a referee does not provide a referral address when staking, no referral bonuses are distributed.<br>

## Claim

### Referee claim process

Referees — users who staked tokens (e.g., stETH) and may have used a referral address — can claim their accumulated MOR rewards by calling the [`claim`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#claim) function.

### Referrer Claim Process

Referrers — users whose referral address was used during staking — accumulate MOR bonuses based on the total amount of deposits made by referees and the tier multiplier they qualify for.&#x20;

{% hint style="info" %}
For example, if all referees have a combined virtual stake of 10 stETH, then the referrer’s tier will be **Tier 1**, and the bonus will be 5%.

This means the referrer will receive a virtual stake equal to 5% of 10 stETH, which is 0.5 virtual stETH, and will be eligible to receive rewards based on that 0.5 virtual stETH amount.
{% endhint %}

```solidity
uint256 referrerVirtualAmount = totalStakedByRefereeVirtualAmount * bonus;
```

To claim their referral rewards, a referrer calls [`claimReferrerTier`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#claimreferrertier).  This mechanism ensures that both types of participants — referees and referrers—can transparently and securely access their rewards, with all lock periods enforced and yield data synchronized across chains.


# Move yield from L1 to L2

This guide explains the precise steps required to transfer the protocol yield from Ethereum (L1) to Arbitrum (L2) using the core contracts of the protocol.

## Move yield to the L1SenderV2 (optional)

Morpheus yield is automatically transferred to the `L1SenderV2` contract from each `DepositPool` whenever any user calls the staking, claiming, or withdrawal functions. Thus, USDC, USDC, stETH, etc., are accumulated on `L1SenderV2`.

If it is necessary to transfer to L2 the maximum yield amount (for example, if there has been no activity on one or several deposit pools for a long time), the contract owner can call the [`withdrawYield`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/distributor#withdrawyield) function on the `Distributor` contract. It will calculate the current yield of the asset and transfer it to the `L1SenderV2` address.

At this step, it is possible to collect the maximum yield from all deposit pools, if necessary.

```solidity
function withdrawYield(uint256 rewardPoolIndex_, address depositPoolAddress_) external;
```

## Convert USDC, USDT, wBTC... to wstETH (optional)

All yield from the Morpheus protocol must be converted to wstETH before being sent to Arbitrum.

Yield from different deposit pools is accrued in different tokens (USDC, USDC, wBTC...). The purpose of this step is to convert this yield to wstETH. To do this, the contract owner need to call the [`swapExactInputMultihop`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/l1senderv2#swapexactinputmultihop) function on the `L1SenderV2` contract.

The exception is the stETH token, which will be automatically converted to wstETH at the next step and does not require this conversion.

If this step is skipped, the yield from deposit tokens that has not been converted to wstETH (except stETH) will not be transferred to L2.

```solidity
function swapExactInputMultihop(
  address[] calldata tokens_,
  uint24[] calldata poolsFee_,
  uint256 amountIn_,
  uint256 amountOutMinimum_,
  uint256 deadline_
) external onlyOwner returns (uint256) 
```

## &#x20;Transfer wstETH to Arbitrum

At this step, the protocol yield is transferred to Arbitrum via the Arbitrum bridge. The function converts stETH to wstETH, calculates the wstETH balance (including the previous step where yield from other tokens was swapped to wstETH), and transfers all wstETH to L2. To do this, the contract owner need to call the [`sendWstETH`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/l1senderv2#sendwsteth) function on the `L1SenderV2` contract.

```solidity
function sendWstETH(
  uint256 gasLimit_,
  uint256 maxFeePerGas_,
  uint256 maxSubmissionCost_
) external payable onlyOwner returns (bytes memory)
```


# Protocol management

This page is intended for protocol owners and explains how to change protocol parameters.

## How to find an ABI for calling smart contract functions via multisig or code?

Almost all smart contracts use the UUPS proxy pattern. This means that all transactions are sent to the address of the proxy contract; these addresses are listed in the [documentation](/smart-contracts/documentation/distribution-protocol/deployed-contracts). The ABI, however, should be taken from the implementation. You can find it using various services, for example, on Etherscan you need to do the following:

1. Open the smart contract.
2. Go to the “Contract” tab and check the contract name. If it contains the word "proxy", continue to the next step. If not, skip to step 6.
3. Click “Read as Proxy.”
4. Open the smart contract shown as the implementation.
5. Go to the “Contract” tab.
6. Confirm this is what you need by comparing the name of the contract you are looking for with what is shown on Etherscan.
7. Scroll to the very bottom and copy the ABI.

*This contract is a proxy, as the contract name contains "Proxy".*

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

*The implementation address can be found as shown in the screenshot.*

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

*This contract is an implementation or valid searched contract, as the contract name doesn't contains "Proxy".*

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

*The ABI example.*

<figure><img src="/files/1fx5S7ZHMmssxS8LF0aV" alt=""><figcaption></figcaption></figure>

## Upgrade the protocol to the new version

To upgrade the protocol to a new version, the contract owner need to call the upgrateTo() function on the target contract

```solidity
function upgradeTo(address newImplementation) public;
```

Where `newImplementation` will be the address of the new version of the smart contract. The implementation must have the correct contract, which name you can double-check on Etherscan in the "Contract" section.

## Updating bucket limits in the deposit pool

To set new limits for a bucket in a `DepositPool`, the contract owner need to call the [`setRewardPoolProtocolDetails()`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#setrewardpoolprotocoldetails) function on the [`DepositPool`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool) contract.&#x20;

```solidity
function setRewardPoolProtocolDetails(
  uint256 rewardPoolIndex_,
  uint128 withdrawLockPeriodAfterStake_,
  uint128 claimLockPeriodAfterStake_,
  uint128 claimLockPeriodAfterClaim_,
  uint256 minimalStake_
) public onlyOwner;
```

This will update the following parameters:

* `rewardPoolIndex_` - the reward pool ID (bucket ID, `0` for the Capital users).
* `withdrawLockPeriodAfterStake_` - Lock period for the withdrawals after the stake transaction, seconds.
* `claimLockPeriodAfterStake_` - Lock period for claims after the stake transaction, seconds.
* `claimLockPeriodAfterClaim_` -Lock period for claims after the claim transaction, seconds.
* `minimalStake_` - Minimal staking amount for the user, wei.

Notes:

* Transaction cannot change one parameter separately. If only one or several parameters are changed, the rest must be duplicated to the transaction params.
* Be careful with the token amount decimals - use the same number of decimals as used by the deposit token.
* To check the changes or the current state, call the [`rewardPoolsProtocolDetails()`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#rewardpoolsprotocoldetails) function on the `DepositPool` contract.
* Changes will ONLY apply to the `DepositPool` where the function was called. To make changes to other `DepositPool`, the contract owner need to execute this transaction on each individual deposit pool.

## Updating referral tiers in the deposit pool:

To set new referral tiers for a bucket in a `DepositPool`, the contract owner need to call the [`editReferrerTiers()`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#editreferrertiers) function on the [`DepositPool`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool) contract.&#x20;

```solidity
function editReferrerTiers(
  uint256 rewardPoolIndex_,
  ReferrerTier[] calldata referrerTiers_
) external onlyOwner;
```

This will update the following parameters:

* `rewardPoolIndex_` - the reward pool ID (bucket ID, `0` for the Capital users).
* `referrerTiers_` - the referrer tiers structs array:
  * `amount` - the minimal token amount for the tier, wei.
  * `multiplier` - the multiplier for the tier, where 1% = 0.01 \* 10<sup>25</sup>.

Example: `editReferrerTiers(0, [ {3.5*10^18; 0.03 * 10^25}, {35*10^18; 0.04 * 10^25}, ...]);`

Notes:

* Transaction cannot change one parameter separately. If only one or several parameters are changed, the rest must be duplicated to the transaction params.
* Be careful with the token amount decimals - use the same number of decimals as used by the deposit token.
* To check the changes or the current state, call the [`referrerTiers()`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#referrertiers) function on the `DepositPool` contract.
* Changes will ONLY apply to the `DepositPool` where the function was called. To make changes to other `DepositPool`, the contract owner need to execute this transaction on each individual deposit pool.


# Unlock wstETH on L2 when it gets stuck

Sometimes, the Arbitrum Bridge does not transfer tokens on Arbitrum, and the reason for this behavior is currently unknown. This guide explains how we can resolve this issue.

{% hint style="info" %}
**If more than 3 days have passed since you sent the transaction to L1 and the tokens have not been received on L2, these tokens may be lost.**
{% endhint %}

The following conditions must be met before proceeding:

* You have a transaction on L1 that has been successfully accepted by the network
* More than 1 hour has passed since the token bridge transaction was sent. Usually, the transfer takes up to 15 minutes, but it’s better to wait a bit longer.

## Solution

#### Step 1. Make sure the transaction on L1 was successfully sent

To identify the problem, you’ll need the `L1Sender` address (any version). Go to the *"Token Transfers (ERC-20)"* tab and look for the problematic transaction that was accepted on L1, but you know the tokens were not received on L2. You can easily identify it because the *"Token"* column will show wstETH.

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

#### Step 2. Find the token receiver on L2

In the `L1Sender` contract, go to the *"Contract" → “Read as Proxy”*, find the `arbitrumBridgeConfig` parameter, and copy the receiver address on L2.

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

#### Make sure the tokens have not arrived on L2

Open the receiver address on L2 and go to the *"Token Transfers (ERC-20)"* tab. Look for the token deposit transaction; the token amount should be approximately the same as the amount you sent on L1 (you can find this in step 1). If, within an hour, the token amount from step 1 has not arrived on L2 — that is, if you don’t find such a transaction — proceed to the next step. If you’re reading this guide, you shouldn’t find the transaction on L2.

#### Resolve the problem

Go to the [Arbitrum Bridge explorer](https://portal.arbitrum.io/bridge?destinationChain=ethereum\&sanitized=true\&sourceChain=arbitrum-one\&tab=tx_history), and find the *"Bridge"* section with the *"Txn History"*. In the search field, enter the [`L1Sender`](/smart-contracts/documentation/distribution-protocol/deployed-contracts#ethereum-mainnet) address, as this is the address that sent tokens to the bridge. If there’s a problem, you should see a transaction with an error on L2 and a *"Retry"* button. Click *"Retry"*  and confirm the transaction (anyone can do this). After the transaction is completed, within a couple of minutes, the tokens should be transferred to L2.

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

{% hint style="info" %}
The screenshot shows an incorrect address in the search field, please disregard this. Enter the valid `L1Sender` address.
{% endhint %}


# Guides

This section contains detailed technical guides covering all aspects of protocol interaction — from staking and reward claiming to cross-chain liquidity transfers.

Each guide focuses on a specific feature, explaining what it does, how it works, what parameters it accepts, and how to use it correctly.

If you’re already familiar with the protocol architecture, use these guides as a technical reference.&#x20;

{% hint style="info" %}
This section is currently under development.&#x20;
{% endhint %}


# MOR distribution. Step #1

This document describes how MOR token rewards are distributed across deposit pools within the protocol.

## Overview

The `Distributor` contract is responsible for periodically allocating MOR rewards to registered deposit pools under a specific reward pool. The distribution process ensures that each deposit pool receives a fair share of MOR tokens based on its generated yield and token value in USD.

## Reward distribution flow

The distribution of MOR tokens is executed through the [`distributeRewards`](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/distributor#distributedrewards) function and follows the steps below:

#### 1. Fetch Emission Rewards from RewardPool

The `Distributor` contract queries the `RewardPool` contract to calculate the total amount of MOR tokens to emit for a given reward pool over the elapsed time period. This is based on a linear decay model defined per pool.

```solidity
uint256 rewards = rewardPool.getPeriodRewards(
  rewardPoolIndex,
  lastCalculatedTimestamp,
  uint128(block.timestamp)
);
```

The contract updates the `rewardPoolLastCalculatedTimestamp` to the current block timestamp after fetching.

#### 2. Update Token Prices for Each Deposit Pool

The `Distributor` updates USD prices for all deposit tokens in the reward pool using Chainlink data feeds:

```solidity
bytes32 chainLinkPathId = chainLinkDataConsumer.getPathId(depositPool.chainLinkPath);
uint256 price = chainLinkDataConsumer.getChainLinkDataFeedLatestAnswer(chainLinkPathId);
```

This ensures that all token values are normalized to the same unit (USD) before comparison.

#### 3. Calculate USD Yield Per Deposit Pool

For each deposit pool, the protocol calculates the **USD-denominated yield**:

```solidity
uint256 yield = (tokenBalance - lastUnderlyingBalance).to18(decimals) * tokenPrice;
```

* `tokenBalance` - current token or aToken balance held by the contract.
* `lastUnderlyingBalance` - previously recorded balance (after last reward allocation).
* `to18()` - utility to normalize token decimals to 18.
* `tokenPrice` - latest USD price from Chainlink.

The `lastUnderlyingBalance` is updated after this step.

#### 4. Compute Yield Shares and Assign Rewards

Once all yields are collected and expressed in USD, the contract calculates the **relative share** of each deposit pool:

```solidity
uint256 rewardShare = (poolYield * totalRewards) / totalYield;
```

* `poolYield` - USD yield of the deposit pool.
* `totalYield` - sum of all deposit pool yields.
* `totalRewards` - emission amount retrieved from `RewardPool`.

Rewards are then added to the `distributedRewards` mapping:

```solidity
distributedRewards[rewardPoolIndex][depositPoolAddress] += rewardShare;
```

If `totalYield` is zero, rewards are temporarily stored in `undistributedRewards`.

## Notes

* For private pools (strategy `NO_YIELD`), all rewards go to the only pool registered under that reward index.
* The reward assignment is proportional to real yield, meaning pools with higher dollar-denominated yield get more MOR.

***


# MOR distribution. Step #2

The `DepositPool` contract is responsible for the internal allocation of MOR tokens among participants who have staked tokens in the pool. While the total amount of MOR rewards is calculated and assigned per pool by the external `Distributor` contract, the `DepositPool` determines how those rewards are split among individual users.

## Staking and virtual stake

When a user deposits tokens, they are immediately forwarded to the `Distributor` contract for yield generation. However, within `DepositPool`, the user’s deposit, applied multipliers (such as power factor bonuses or referral boosts), and resulting virtual stake are recorded. The virtual stake is calculated by multiplying the user’s actual deposit by their multipliers, thus capturing not just the amount staked but also the user’s commitment and contribution to the protocol.

## Daily MOR allocation and cumulative reward coefficient

Unlike yield sources like Aave that accrue rewards continuously, stETH generates yield via a rebasing mechanism once per day. As a result, MOR distribution from the `Distributor` to each `DepositPool` also happens daily. This timing constraint ensures alignment with stETH’s yield schedule.

Internally, each DepositPool uses a cumulative reward coefficient to represent how many MOR tokens have been distributed per unit of virtual stake. When new MOR tokens are allocated to the pool, the coefficient is increased accordingly, reflecting the new available rewards.

## Reward Calculation Formula

User rewards are calculated lazily — that is, only when a user interacts with the contract (e.g., stake, withdraw, or claim), rather than updating every user on each reward deposit. The calculation is performed using the following logic:

```solidity
uint256 userReward = pendingRewards + virtualStake * (poolRewardCoefficient - userRewardCoefficient);
```

* `pendingRewards` - rewards that were calculated after the stake or withdrawal of depositToken — that is, after the user’s share was modified.
* `virtualStake`  - the user’s current stake after applying multipliers.
* `poolRewardCoefficient` - the current accumulated MOR per unit of virtual stake across the entire pool.
* `userRewardCoefficient` - the coefficient stored at the time of the user’s last interaction.

The `poolRewardCoefficient` is updated globally when new rewards are distributed. It is calculated as:

```solidity
uint256 poolRewardCoefficient += distributedRewards / totalVirtualStake;
```

* `distributedRewards` - is the amount of MOR tokens allocated to the pool during distribution.
* `totalVirtualStake` - is the sum of all users’ virtual stake (after applying lock/referral multipliers) at the time of distribution.

This model allows each user’s reward to be efficiently and fairly computed based on the delta in the coefficient since their last update.

### Claiming and Unstaking

When a user claims MOR tokens or unstakes from the pool, the contract first updates their reward using the above formula. Then, it issues the corresponding MOR amount and updates the user’s stored coefficient to the latest global value. This ensures that each user receives exactly their fair share of the distributed tokens.

### Design Advantages

By utilizing a cumulative coefficient and lazy updates, the `DepositPool` can support a large number of users without incurring high gas costs on reward distribution. While it doesn’t determine the total amount of MOR emitted, it guarantees an efficient and accurate internal distribution that reflects both user behavior and their contribution to the system.


# Protocol yield generation

## Overview

This document describes how the protocol generates yield from user deposits, how that yield is handled based on strategy type, and under what conditions it is sent to the `L1SenderV2` contract for cross-chain reward minting.

## Yield generation overview

When users stake tokens into deposit pools, those tokens may be used in different yield strategies, depending on the pool configuration. The protocol currently supports the following strategies:

* `AAVE` - token is deposited into Aave to generate yield.
* `NO_YIELD` - token is not used in any external protocol. This is typically used for `stETH`.
* `NONE` - no yield logic is applied (only for private buckets without real stake).

## Strategy-Specific Deposit Behavior

When a user calls `supply()`

#### For AAVE Strategy:

* The user transfers the underlying `token` to the `Distributor`.
* The `Distributor` supplies the token to the Aave protocol via `AaveIPool.supply()`.
* Yield is later measured by checking the `aToken` balance of the `Distributor`.

#### For NO\_YIELD Strategy (e.g., `stETH`):

* The user transfers `stETH` to the `Distributor`.
* It is **not** deposited anywhere; yield is not actively generated.
* Instead, the `stETH` is held and passively earns staking rewards (as per Lido).

## Reward Distribution Timing and Constraints

Rewards are distributed using `distributeRewards()` which performs the following:

1. **Fetch emitted MOR -** calls `RewardPool.getPeriodRewards()` using the last distribution timestamp.
2. **Check if distribution is due**: public pools must respect `minRewardsDistributePeriod` (e.g., once per day).
   * This is enforced **because `stETH` yield is not readable on-chain** per second or block. It's accrued slowly, and daily intervals allow consistent accounting.
3. **Update Prices**:
   * For each deposit pool in the reward pool, the price of the deposit token is fetched from Chainlink (via `ChainLinkDataConsumer`).
   * This allows yield across tokens (USDC, WETH, etc.) to be normalized to a dollar value.
4. **Calculate Yield Per Pool.** See [MOR distribution. Step #1](/smart-contracts/documentation/distribution-protocol/v7-protocol/guides/mor-distribution.-step-1)
5. **Calculate Pool Shares.** See [MOR distribution. Step #1](/smart-contracts/documentation/distribution-protocol/v7-protocol/guides/mor-distribution.-step-1)
6. **Update State.** See [MOR distribution. Step #1](/smart-contracts/documentation/distribution-protocol/v7-protocol/guides/mor-distribution.-step-1)

## Transferring Yield to L1SenderV2

The protocol does not retain accrued yield within the `Distributor` contract. Instead, yield is extracted and forwarded to `L1SenderV2` selectively — only for the specific `DepositPool` that triggers the operation.

At the end of a yield cycle (e.g., daily), when any function (e.g., `supply`, `withdraw`, or `withdrawYield`) is called on a given deposit pool, the `Distributor` contract:

* Calls `distributeRewards` to calculate and assign MOR rewards based on relative yield of all deposit pools in the same reward pool.
* Then calls `_withdrawYield` only for the `DepositPool` involved in the transaction, transferring its actual yield to `L1SenderV2`.

Yield is transferred using the following logic:

* For `AAVE`:
  * Calls `AaveIPool.withdraw()` to redeem `aTokens`.
  * Transfers the withdrawn tokens to `L1SenderV2`.
* For `NO_YIELD`:
  * Transfers the excess tokens directly (if any) to `l1SeL1SenderV2nder`.

Once the tokens are with `L1SenderV2`, they can be:

* Bridged to Arbitrum.
* Used for minting MOR rewards for users via `sendMintMessage()`.

## Notes

* `stETH` pools use `NO_YIELD` because stETH natively accrues rewards via rebasing.
* The yield on `stETH` cannot be measured at each block — hence daily distribution is preferred.
* Price-based yield normalization ensures fair distribution even when token values vary.


# MOR emission logic

The `LinearDistributionIntervalDecrease` library implements a reward calculation strategy designed for protocols that emit a fixed token amount per interval, with a predictable linear decrease in the emission rate over time. This pattern is used for long-term token emission schemes (e.g., MOR) that reward staking participants based on when they joined and how long they stayed.

## Overview

The key concept is *linear emission with interval-based reduction*. Instead of updating user rewards every second, the protocol defines a base reward amount that decreases linearly every fixed time interval (e.g., s). This model balances emission precision and computational efficiency, making it ideal for large-scale staking systems.

## **Emission scheme params**

* `initialAmount` — the starting reward amount per interval (e.g., 1000 tokens per day).
* `decreaseAmount` — how much the reward decreases *per interval* (e.g., 10 tokens less per day).
* `interval` — time in seconds (e.g., 86400 for daily).
* `payoutStart` — timestamp when emissions start.
* `startTime` / `endTime` — the specific time window to compute rewards for.

Internally, reward calculation over a range (e.g., user staking from day 4 to day 10) is split into three parts:

1. **Partial First Interval**

   If the time window begins *within* an interval (not at its start), a proportional reward is computed based on how much of that interval is included.
2. **Full Intervals in the Middle**

   If the period spans multiple full intervals, the total reward for these is computed efficiently using an arithmetic sum of decreasing values:

```
        initialReward * ip_ - (decreaseAmount_ * (ip_ * (ip_ - 1))) / 2
```

&#x20;       This handles the geometric drop without looping over each interval.

3. **Partial Last Interval**

   If the time window ends *within* an interval, a proportional reward for the trailing part is added, similar to the first part.

If the input `endTime_` exceeds this cutoff, it’s clamped to avoid negative rewards.<br>

## Emission cutoff

The system prevents reward underflow by computing a maximum emission end time. This is the timestamp when the emissions would naturally reduce to zero:

```
maxIntervals = ceil(initialAmount / decreaseAmount)
maxEndTime = payoutStart + maxIntervals * interval
```


# Private buckets (pools)

## Overview

Private buckets (builders, compute, coders...) are a special mechanism available only within the stETH `DepositPool` contract. Unlike public staking (coders staking), where users deposit stETH tokens into the contract, private buckets allow protocol administrators to assign virtual stake balances to users without requiring any on-chain deposit of tokens.

Private buckets are particularly useful for allocating rewards to test participants, strategic partners, investors, or any group of users who should receive emissions without actively staking tokens. Internally, private buckets do not exist as a separate structure—they are managed through dedicated administrative functions that set the relevant parameters per user in the existing reward pools.

## Add  new private stakers

The reward logic for private bucket participants is identical to that of public users: rewards are accrued based on the user’s virtual stake, in proportion to the total stake in the pool, and follow the same emission rules. However, instead of interacting with the contract directly, users in private buckets are manually added by an administrator with [manageUsersInPrivatePool](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#manageusersinprivatepool), who assigns them a virtual stake amount, an optional lock period before rewards can be claimed, and, if relevant, a referrer address for referral bonuses.

## Claim MOR rewards

To actually receive MOR rewards, users in private buckets must explicitly call the [claim](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#claim) function, just like any other participant. They must provide the appropriate `poolId` corresponding to the bucket pool they’ve been assigned to. The contract treats their virtual stake identically to real deposits during reward distribution. However, since there are no tokens physically deposited, actions such as withdraw or restake are not applicable for private bucket participants.

In addition, the contract provides the [claimFor](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#claimfor) function, which allows one address to claim rewards on behalf of another. This is permitted if the caller has been explicitly whitelisted via the [setClaimSender](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#setclaimsender) function, or if the staker has set a `claimReceiver` using [setClaimReceiver](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/depositpool#setclaimreceiver).

This feature is particularly useful in the context of private buckets. For example, if an entire builder bucket is assigned to a single multisig address, the multisig can set a public `claimReceiver`. In this case, any user can trigger a claim for the builder bucket using `claimFor`, but the actual reward tokens on L2 will always be sent to the receiver address that the multisig specified.

## Summary

In summary, private buckets offer a flexible way for the protocol to assign reward eligibility without requiring capital to be locked on-chain, while fully integrating into the broader reward distribution system.


# Changelog

From v5 to v7

## DistributionV5 -> DepositPool

The `DistributionV5` contract was renamed to `DepositPool` because the old name no longer reflects its role — the core reward distribution logic has been moved out of this contract.

This contract no longer accumulates or holds user stake balances directly for yield generation. Instead, all deposits are forwarded to the `Distributor` contract, which manages the real token flow and yield accounting.

### Storage Refactoring and Responsibility Separation

Many of the storage variables from `DistributionV5` have been deprecated and renamed to `unusedStorage` to maintain upgradeability alignment. The actual data and responsibilities tied to these variables were migrated to more specialized contracts:

* `rewardPools` and `l1Sender` data moved to `RewardPool` and `Distributor` .
* `poolsLimits` moved to `rewardPoolsProtocolDetails` .
* Introduced new storage fields such as:
  * `distributor` — central reward distributor.
  * `rewardPoolsProtocolDetails` — configuration per reward pool.
  * `isMigrationOver` — flag to mark pool-level migration completion.

```solidity
/** @dev UPGRADE `DepositPool`, v7. Storage updates, add few deposit pools. */
/** @dev This flag determines whether the migration has been completed. */
bool public isMigrationOver;

/** @dev `Distributor` contract address. */
address public distributor;

/** @dev Contain information about rewards pools needed for this contract. */
mapping(uint256 => RewardPoolProtocolDetails) public rewardPoolsProtocolDetails;
/** @dev UPGRADE `DepositPool`, v7 end. */

```

**Motivation**: cleaner architecture, modularity, upgrade-safe alignment.

### Delegated Claim Functionality

Two mappings were introduced to support trusted claim delegation:

* `claimSender`: allows a staker to whitelist addresses permitted to claim on their behalf.
* `claimReceiver`: enables users to automatically set L2 receiver and allow anyone to claim behalf the staker.

```solidity
/** @dev UPGRADE `DistributionV6` storage updates, add addresses allowed to claim. Add whitelisted claim receivers. */
mapping(uint256 => mapping(address => mapping(address => bool))) public claimSender;
mapping(uint256 => mapping(address => address)) public claimReceiver;
/** @dev UPGRADE `DistributionV6` end. */

```

**Motivation**: unlocks possibility to allow anyone claim behalf staker, for example for Builder bucket.

### One-Time Migration Mechanism

New `migrate` function allows a pool to finalize its state migration after a contract upgrade. If there are any extra tokens (yield), they are forwarded to the `Distributor`, and the pool gets marked as migrated.

```solidity
function migrate(uint256 rewardPoolIndex_) external onlyOwner {
  require(!isMigrationOver, "DS: the migration is over");
  ...

  IDistributor(distributor).supply(rewardPoolIndex_, totalDepositedInPublicPools);

  isMigrationOver = true;

  emit Migrated(rewardPoolIndex_);
}
```

**Motivation**: ensures smooth, non-breaking transition to the new verision.

### Distributor-Centric Reward Logic

Part of reward distribution delegated to the `Distributor` contract. This affects related changes in many functions that cannot be described block by block and require reviewing the pull request.

**Motivation**: separate part of reward calculations to implement the new logic.

## L1MessageReceiver -> L1MessageReceiverV2

### Centralized Integration via Distributor

The `L1MessageReceiverV2` contract no longer interacts directly with the `DistributionV5` contract. Instead, it now connects through the unified `Distributor` contract.

This design ensures that the system maintains a single authoritative point for defining and interacting with the `L1MessageReceiverV2`.

**Motivation:** since there can be multiple `DepositPool` contracts, it’s inefficient and redundant to store the `L1MessageReceiverV2` address in each one — moving this to the `Distributor` improves maintainability and consistency.

### Yield Management and Uniswap Integration

As `L1MessageReceiverV2` is now responsible for storing and managing the protocol’s accumulated yield, it includes new functionality for interacting with Uniswap.

**Motivation:** this allows the contract to actively manage yield (e.g., perform token swaps) before bridging operations.

## RewardPool

The `RewardPool` contract now contains significant portions of logic that were previously handled by the `DistributionV5` contract. This change reflects a broader architectural refactor that distributes responsibilities across dedicated modules.

The `RewardPool` contract now encapsulates the emission logic that was previously part of `DistributionV5`. Specifically, it is responsible for calculating MOR token emissions over time, determining the reward amounts to be distributed in each period, and managing the allocation of rewards across predefined user buckets (such as Capital, Builder, Compute, etc.).&#x20;

**Motivation:** by consolidating this logic, the system ensures consistency and avoids duplication across multiple `DepositPool` instances.

## ChainLinkDataConsumer and Distributor

The new protocol architecture introduces the `ChainLinkDataConsumer` and `Distributor` contracts to support expanded yield strategies for newly added staking tokens. These contracts are required due to the introduction of additional yield-generating mechanisms.

The `Distributor` contract handles the logic for reward allocation and incorporates integration with Aave, where deposited tokens can be used to generate yield. However, the actual Aave yield is not returned to users — instead, it is used to inform the protocol’s internal reward calculations and determine how much MOR should be distributed to each `DepositPool`.

The `ChainLinkDataConsumer` contract integrates with Chainlink oracles to fetch real-time price data  necessary for calculating MOR rewards.<br>

## Links

<https://github.com/MorpheusAIs/SmartContracts/pull/53>


# Risks

### **Upgradeability Risks**

Most contracts use the `UUPSUpgradeable` pattern. Mistakes during upgrades can lead to data loss or funds being locked.

### **Access Control Risks**

Many functions are protected by the `onlyOwner` modifier, concentrating power in a single address. If the owner's private key is compromised, an attacker could control all critical functions: changing parameters, withdrawing funds, or upgrading contracts.

### **External Dependency Risks**

The protocol relies on third-party contracts (Aave, Chainlink, Uniswap, LayerZero, Arbitrum bridges). Vulnerabilities, upgrades, or failures in these dependencies can lead to loss of funds or protocol downtime.

### **Oracle Risks**

The `ChainLinkDataConsumer` contract fetches prices via Chainlink. If the oracle is compromised or becomes unavailable, the protocol may use incorrect data, leading to faulty calculations, loss of funds, or attacks on protocol solvency.

### **Token Transfer and Approval Risks**

The use of `SafeERC20` and `TransferHelper` reduces, but does not eliminate, risks associated with non-standard token implementations (e.g., re-entrancy attacks, unexpected behavior). Errors in transfer logic can result in loss of funds.

### **Cross-Chain Risks**

Contracts like `L1SenderV2` and `L2TokenReceiverV2` interact with bridges and cross-chain messaging. This is a complex area where attacks on bridges, message delays, duplication, or loss can lead to funds being lost or locked.

### **Centralization and Governance Risks**

Centralized control over key parameters (oracles, pools, bridges) creates a single point of failure and the potential for abuse.


# Deployed contracts

## Mainnet

### Ethereum Mainnet

<table><thead><tr><th width="305.203125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>DepositPool(stETH)</code> </td><td><a href="https://etherscan.io/address/0x47176b2af9885dc6c4575d4efd63895f7aaa4790"><kbd>0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790</kbd></a></td></tr><tr><td><code>DepositPool(wETH)</code> </td><td><a href="https://etherscan.io/address/0x9380d72abbd6e0cc45095a2ef8c2ca87d77cb384"><kbd>0x9380d72aBbD6e0Cc45095A2Ef8c2CA87d77Cb384</kbd></a></td></tr><tr><td><code>DepositPool(wBTC)</code> </td><td><a href="https://etherscan.io/address/0xde283f8309fd1aa46c95d299f6b8310716277a42"><kbd>0xdE283F8309Fd1AA46c95d299f6B8310716277A42</kbd></a></td></tr><tr><td><code>DepositPool(USDC)</code> </td><td><a href="https://etherscan.io/address/0x6cce082851add4c535352f596662521b4de4750e"><kbd>0x6cCE082851Add4c535352f596662521B4De4750E</kbd></a></td></tr><tr><td><code>DepositPool(USDT)</code> </td><td><a href="https://etherscan.io/address/0x3b51989212bedab926794d6bf8e9e991218cf116"><kbd>0x3B51989212BEdaB926794D6bf8e9E991218cf116</kbd></a></td></tr><tr><td><code>L1SenderV2</code></td><td><a href="https://etherscan.io/address/0x2efd4430489e1a05a89c2f51811ac661b7e5ff84"><kbd>0x2Efd4430489e1a05A89c2f51811aC661B7E5FF84</kbd></a></td></tr><tr><td><code>ChainLinkDataConsumer</code></td><td><a href="https://etherscan.io/address/0xd182263d06fdc463c96190005d6359cc3d3bbc5e"><kbd>0xd182263d06FDC463c96190005D6359CC3d3Bbc5e</kbd></a></td></tr><tr><td><code>RewardPool</code></td><td><a href="https://etherscan.io/address/0xb7994de339aee515c9b2792831cd83f3c9d8df87"><kbd>0xb7994dE339AEe515C9b2792831CD83f3C9D8df87</kbd></a></td></tr><tr><td><code>Distributor</code></td><td><a href="https://etherscan.io/address/0xdf1ac1ac255d91f5f4b1e3b4aef57c5350f64c7a"><kbd>0xDf1AC1AC255d91F5f4B1E3B4Aef57c5350F64C7A</kbd></a></td></tr><tr><td><code>LinearDistributionIntervalDecrease</code></td><td><a href="https://etherscan.io/address/0xfb1a7d49ceb0ee8c929d67eb9762366506a4825c"><kbd>0xfb1a7d49ceb0ee8c929d67eb9762366506a4825c</kbd></a></td></tr><tr><td><code>LockMultiplierMath</code></td><td><a href="https://etherscan.io/address/0x345b8b23c38f70f1d77560c60493bb583f012cb0"><kbd>0x345b8b23c38f70f1d77560c60493bb583f012cb0</kbd></a></td></tr><tr><td><code>LogExpMath</code></td><td><a href="https://etherscan.io/address/0x345b8b23c38f70f1d77560c60493bb583f012cb0"><kbd>0x345b8b23c38f70f1d77560c60493bb583f012cb0</kbd></a></td></tr><tr><td><code>ReferrerLib</code></td><td><a href="https://etherscan.io/address/0x9a397c638bd9611539e7992b32e206102e6d2965"><kbd>0x9a397c638bd9611539e7992b32e206102e6d2965</kbd></a></td></tr></tbody></table>

#### Graph for the v7

<https://api.studio.thegraph.com/query/73688/morpheus-mainnet-v-2/version/latest>

### Arbitrum One

<table><thead><tr><th width="305.29296875">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>L2MessageReceiver</code></td><td><kbd>0xd4a8ECcBe696295e68572A98b1aA70Aa9277d427</kbd></td></tr><tr><td><code>L2TokenReceiver</code></td><td><kbd>0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790</kbd></td></tr></tbody></table>

## Testnet

### Ethereum Sepolia

#### v5

<table><thead><tr><th width="294.5">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>DistributionV5</code></td><td><kbd>0x7c46d6bebf3dcd902eb431054e59908a02aba524</kbd></td></tr><tr><td><code>L1Sender</code></td><td><kbd>0x44Cdf2B6f357Ef5e40c9756e4774067b719D28f8</kbd></td></tr><tr><td><code>stETH</code></td><td><kbd>0xa878Ad6FF38d6fAE81FBb048384cE91979d448DA</kbd></td></tr></tbody></table>

#### v7

<table><thead><tr><th width="294.79296875">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>DepositPool (stETH)</code></td><td><kbd>0xFea33A23F97d785236F22693eDca564782ae98d0</kbd></td></tr><tr><td><code>DepositPool (LINK)</code></td><td><kbd>0x7f4f17be21219D7DA4C8E0d0B9be6a778354E5A5</kbd></td></tr><tr><td><code>Distributor</code></td><td><kbd>0x65b8676392432B1cBac1BE4792a5867A8CA2f375</kbd></td></tr><tr><td><code>L1SenderV2</code></td><td><kbd>0x85e398705d7D77F1703b61DD422869A67B3B409d</kbd></td></tr><tr><td><code>RewardPool</code></td><td><kbd>0xbFDbe9c7E6c8bBda228c6314E24E9043faeEfB32</kbd></td></tr><tr><td><code>stETH</code></td><td><kbd>0xa878Ad6FF38d6fAE81FBb048384cE91979d448DA</kbd></td></tr><tr><td><code>LINK</code></td><td><kbd>0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5</kbd></td></tr></tbody></table>

#### Graph for the v7

<https://api.studio.thegraph.com/query/73688/morpheus-ethereum-sepolia/version/latest>

### Arbitrum Sepolia

<table><thead><tr><th width="203.89453125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>L2MessageReceiver</code></td><td><kbd>0xd4a8ECcBe696295e68572A98b1aA70Aa9277d427</kbd></td></tr><tr><td><code>L2TokenReceiver</code></td><td><kbd>0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790</kbd></td></tr></tbody></table>


# Builders protocol

The protocol is deployed on Base and Arbitrum One networks. It is designed to distribute MOR rewards among builders bucket based on user staking activity.

## Changelog

#### v1

Includes the basic version of the protocol. Anyone can create a Subnet by defining a set of parameters. Users can stake MOR tokens within a specific Subnet. Based on the total amount staked in each Subnet, that Subnet receives a share of the global MOR rewards, calculated proportionally to the total stake across all Subnets.

Each subnet has a `claimLockEnd` parameter, which defines a period during which rewards cannot be claimed. In return, the Subnet receives a multiplier to its stake, increasing its reward share.

Rewards are allocated to subnets when the Morpheus multisig transfers MOR tokens to a dedicated protocol contract. After that, any interaction — staking, withdrawing, or claiming — triggers reward calculations. Only the subnet admin can claim rewards. The distribution of those rewards among individual participants is handled outside the current protocol scope. The more frequently the multisig sends MOR tokens for distribution, the fairer the reward distribution across subnets will be.

#### v2 - current

Contains a fix for a bug related to the incorrect calculation of virtual stake when a high `claimLockEnd` was set for a Subnet. The issue caused the virtual stake to grow disproportionately, distorting reward distribution among Subnets.

#### v3

Was under development but ultimately rejected due to a mismatch with the current state of the protocol and its long-term goals. The proposed changes in v3 were deemed incompatible with the intended architecture and direction of the current protocol.

#### v4 - proposed

This version removes virtual deposits and multipliers, making the `claimLockEnd` mechanism obsolete. Subnet structure has been simplified — the start time and claim lock fields were removed. Instead, a metadata field was added, along with a secondary address allowed to claim rewards on behalf of the Subnet.

Subnet identifiers have been updated to include chainId, allowing subnets with the same name to exist on different blockchains without conflicts. Existing subnets retain their original identifiers.

The reward logic has also changed. Instead of waiting for the Morpheus multisig to send tokens for distribution, the protocol now uses a MOR emission curve to allocate virtual rewards in real time. The multisig is now responsible only for ensuring the reward distribution contract has enough MOR balance to fulfill claims. A dedicated share for the entire network was introduced to enable proper reward calculation across multiple chains.

{% content-ref url="/pages/jC1XGWF1PrqKFFa0JcoX" %}
[v2 Protocol](/smart-contracts/documentation/builders-protocol/v2-protocol)
{% endcontent-ref %}

{% content-ref url="/pages/9iIskLw6oDxqIRZPDu0i" %}
[v4 Protocol](/smart-contracts/documentation/builders-protocol/v4-protocol)
{% endcontent-ref %}


# v2 Protocol

The protocol is a staking and reward distribution system deployed on Base and Arbitrum One. It enables any user to create isolated staking pools, called builder pools, where others can deposit MOR tokens. Each pool has configurable parameters such as minimum deposit, staking start time, and lock periods...

Users stake MOR into these pools, and based on their amount and pool claim lock duration, receive a virtual deposit value that determines their share of rewards. Longer locks yield higher multipliers. Rewards across all pools are calculated based on a shared global rate and distributed proportionally.

Only the pool creator (the builder) can claim the rewards earned by their pool and choose how to distribute them. These rewards come from the `BuildersTreasury`, which is funded by Morpheus protocol administrators.

The system also includes a flexible fee module (`FeeConfig`) that lets protocol owners define claim and withdrawal fees, adding sustainability while keeping builders in full control of their pools.


# Contracts

## Core contracts

### [Builders](/smart-contracts/documentation/builders-protocol/v2-protocol/contracts/builders)

The `Builders` contract serves as the core logic hub of the protocol. It enables the creation and management of builder pools. Each pool is uniquely identified by a name and configured with a set of parameters. Pools can be created by any user, but the builder address assigned during creation becomes the administrator of that pool.

Users can freely stake tokens into any existing pool. The protocol tracks both actual deposits and *virtual deposits* — the latter being weighted values adjusted by a time-based lock multiplier (power factor). This multiplier incentivizes users to hold their tokens for longer periods by increasing their share of rewards. The global reward calculation is based on a rate applied across all builder pools, ensuring fair distribution depending on virtual deposit weight.

Pool administrators have the authority to claim the accumulated rewards of their pool. They can also designate an address to receive those rewards. However, they are not allowed to withdraw user deposits or alter past deposits. The claim process respects claim lock deadlines for the all stakers in the pool.

### [BuildersTreasury](/smart-contracts/documentation/builders-protocol/v2-protocol/contracts/builderstreasury)

The `BuildersTreasury` contract acts as the token vault for reward distribution. It is only callable by the `Builders` contract. When a builder claims rewards, the treasury contract transfers the net reward amount (after applying protocol fees) to the specified receiver address. The pool administrators receives the reward for the entire pool, and they are expected to handle any internal distribution if needed.

Importantly, this contract must be funded by the Morpheus protocol administrators, as all reward calculations are performed on Ethereum and rely on the balance available in this contract. The treasury tracks distributed rewards and current token availability to ensure accurate accounting.

### [FeeConfig](/smart-contracts/documentation/builders-protocol/v2-protocol/contracts/feeconfig)

Fee management is delegated to the `FeeConfig` contract, which defines how much fee should be applied to specific actions like *claiming* or *withdrawing*. The contract owner (administrator of the `FeeConfig` contract) can set a base fee rate, as well as custom fees per operation and per address. Fees are expressed as a percentage and routed to a treasury address.

This modular fee configuration allows the protocol to evolve and adapt to different economic models or integrations, while maintaining strict access control over critical parameters.

## Periphery

### OpenZeppelin

Used extensively across contracts to support secure access control and upgradeability:

* `OwnableUpgradeable` – enables ownership access control.
* `UUPSUpgradeable` – facilitates contract upgradeability via the UUPS (Universal Upgradeable Proxy Standard) pattern.

Links:

* <https://docs.openzeppelin.com/contracts/4.x/access-control>
* <https://docs.openzeppelin.com/contracts/4.x/api/proxy>


# Builders

## Overview

The `Builders` contract is the core component of the protocol. It manages builder pools, allowing users to stake tokens and builders to accumulate and claim MOR rewards based on those stakes.

Each pool is uniquely identified by name and includes parameters such as minimum deposit amount, pool start time, claim lock period, and withdrawal lock time after deposit... Users can deposit tokens into any existing pool, and their effective contribution (virtual deposit) is calculated using a lock multiplier based on how long rewards are locked.

Rewards are not distributed directly to users. Instead, they accumulate at the pool level and can be claimed only by the pool’s builder (admin). Builders then choose how to distribute these rewards off-chain. The global MOR reward rate is calculated across all pools, and each pool receives a share based on its total virtual deposits.

## Key Features

1. Pool creation and configuration: anyone can create a pool with custom parameters; the builder (admin) is assigned at creation.
2. User staking: users stake tokens into any active pool, with lock-based multipliers increasing their contribution weight.
3. Builder-controlled reward claiming: only builders can claim the total pool reward, enabling flexible distribution outside the contract scope.
4. Reward calculation: uses a dynamic rate updated with each user action and proportional to the protocol-wide virtual deposits.
5. Fee system: integrated with `FeeConfig` for applying customizable withdrawal and claim fees.
6. Upgradeable and permissioned: built with UUPS and Ownable patterns for controlled upgrades and ownership-based access.

## Storage

### feeConfig

Address of the `FeeConfig` contract used to calculate protocol fees.

```solidity
address public feeConfig;
```

### buildersTreasury

Address of the `BuildersTreasury` contract which stores and distributes reward tokens.

```solidity
address public buildersTreasury;
```

### depositToken

Address of the MOR token users deposit into builder pools.

```solidity
address public depositToken;
```

### editPoolDeadline

The time window (in seconds) before the pool starts, during which pool parameters can still be edited by the pool admin.

```solidity
uint128 public editPoolDeadline;
```

### minimalWithdrawLockPeriod

Minimum duration (in seconds) after a deposit during which withdrawals are locked.

```solidity
uint256 public minimalWithdrawLockPeriod;
```

### totalPoolData

Aggregated data for all builder pools in the system.

```solidity
TotalPoolData public totalPoolData;

struct TotalPoolData {
  uint256 distributedRewards;
  uint256 rate;
  uint256 totalDeposited;
  uint256 totalVirtualDeposited;
}
```

| Name                    | Description                                                               |
| ----------------------- | ------------------------------------------------------------------------- |
| `distributedRewards`    | Total amount of rewards distributed across all pools. Wei.                |
| `rate`                  | The current reward rate                                                   |
| `totalDeposited`        | Total tokens deposited without applying any multiplier. Wei.              |
| `totalVirtualDeposited` | Total tokens deposited with multiplier (used in reward calculations). Wei |

### builderPools

Mapping of pool ID to pool configuration.

```solidity
mapping(bytes32 => BuilderPool) public builderPools;

struct BuilderPool {
  string name;
  address admin;
  uint128 poolStart;
  uint128 withdrawLockPeriodAfterDeposit;
  uint128 claimLockEnd;
  uint256 minimalDeposit;
}
```

| Name                             | Description                                                                 |
| -------------------------------- | --------------------------------------------------------------------------- |
| `name`                           | The name of the builder project.                                            |
| `admin`                          | The address of the pool administrator (builder).                            |
| `poolStart`                      | Timestamp when the pool becomes active.                                     |
| `withdrawLockPeriodAfterDeposit` | Time period after deposit during which withdrawal is locked. Seconds.       |
| `claimLockEnd`                   | Timestamp after which rewards can be claimed by the builder admin. Seconds. |
| `minimalDeposit`                 | Minimum amount a user must deposit to participate. Wei.                     |

### buildersPoolData

Mapping of pool ID to the current dynamic pool state.

```solidity
mapping(bytes32 => BuilderPoolData) public buildersPoolData;

struct BuilderPoolData {
  uint128 lastDeposit;
  uint256 deposited;
  uint256 virtualDeposited;
  uint256 rate;
  uint256 pendingRewards;
}
```

| Name               | Description                                            |
| ------------------ | ------------------------------------------------------ |
| `lastDeposit`      | Timestamp in seconds of the last deposit into the pool |
| `deposited`        | Total amount deposited without multiplier. Wei.        |
| `virtualDeposited` | Total amount deposited with multipliers applied. Wei.  |
| `rate`             | Current reward rate for the pool                       |
| `pendingRewards`   | Accumulated unclaimed rewards for the pool. Wei.       |

### usersData

Mapping of user address and pool ID to their user-specific data.

```solidity
mapping(address => mapping(bytes32 => UserData)) public usersData;

struct UserData {
  uint128 lastDeposit;
  uint128 claimLockStart;
  uint256 deposited;
  uint256 virtualDeposited;
}
```

| Name               | Description                                                |
| ------------------ | ---------------------------------------------------------- |
| `lastDeposit`      | Timestamp in seconds of the user's last deposit.           |
| `claimLockStart`   | Timestamp when the user activated the reward lock. Seconds |
| `deposited`        | Total tokens the user deposited (raw amount). Wei          |
| `virtualDeposited` | Tokens deposited by user with multiplier applied. Wei.     |

### Fee oprations

The lables for fee operations, uses for fee receiving in the `FeeConfig` contract.

```solidity
bytes32 private constant FEE_WITHDRAW_OPERATION = "withdraw";
bytes32 private constant FEE_CLAIM_OPERATION = "claim";
```

## Write functions for the contract owner

### Builders\_init

Initializes the contract with essential parameters and configuration contracts. This function must be called once after deployment.

```solidity
function Builders_init(
    address depositToken_,
    address feeConfig_,
    address buildersTreasury_,
    uint128 editPoolDeadline_,
    uint256 minimalWithdrawLockPeriod_
) external initializer
```

| Name                         | Description                                                                          |
| ---------------------------- | ------------------------------------------------------------------------------------ |
| `depositToken_`              | Address of the token that users will deposit in builder pools. MOR token.            |
| `feeConfig_`                 | Address of the `FeeConfig` contract used to calculate protocol fees.                 |
| `buildersTreasury_`          | Address of the `BuildersTreasury` contract used to store and distribute rewards.     |
| `editPoolDeadline_`          | Time (in seconds) before pool start when editing is still allowed.                   |
| `minimalWithdrawLockPeriod_` | Minimum lock duration after deposit in seconds before users can withdraw staked MOR. |

### setFeeConfig

Sets the address of the `FeeConfig` contract.

```solidity
function setFeeConfig(address feeConfig_) public onlyOwner
```

| Name         | Description                                      |
| ------------ | ------------------------------------------------ |
| `feeConfig_` | Address of a contract that implements IFeeConfig |

### setBuildersTreasury

Sets the address of the `BuildersTreasury` contract.

```solidity
function setBuildersTreasury(address buildersTreasury_) public onlyOwner
```

| Name                | Description                                             |
| ------------------- | ------------------------------------------------------- |
| `buildersTreasury_` | Address of a contract that implements IBuildersTreasury |

### setEditPoolDeadline

Sets the edit deadline (in seconds) for a builder pools relative to its start time.

```solidity
function setEditPoolDeadline(uint128 editPoolDeadline_) public onlyOwner
```

| Name                | Description                                         |
| ------------------- | --------------------------------------------------- |
| `editPoolDeadline_` | Number of seconds before start when edit is allowed |

### setMinimalWithdrawLockPeriod

Sets the minimum lock period that must pass before a user can withdraw MOR after depositing.

```solidity
function setMinimalWithdrawLockPeriod(
  uint256 minimalWithdrawLockPeriod_
) public onlyOwner
```

| Name                         | Description                                                      |
| ---------------------------- | ---------------------------------------------------------------- |
| `minimalWithdrawLockPeriod_` | Minimum lock period (in seconds) after deposit before withdrawal |

## Write functions

### createBuilderPool<br>

Creates a new builder pool with specific parameters.

```solidity
function createBuilderPool(BuilderPool calldata builderPool_) public
```

| Name           | Description                                                          |
| -------------- | -------------------------------------------------------------------- |
| `builderPool_` | Struct with the new pool’s parameters: name, admin, start time, etc. |

### editBuilderPool

Edits an existing builder pool’s configuration before its edit deadline expires. The caller should be the builder pool admin.&#x20;

```solidity
function editBuilderPool(BuilderPool calldata builderPool_) external
```

| Name           | Description                                                                 |
| -------------- | --------------------------------------------------------------------------- |
| `builderPool_` | Updated struct data of the builder pool to overwrite existing configuration |

### deposit

Allows a user to deposit MOR into a builder pool.

```solidity
function deposit(bytes32 builderPoolId_, uint256 amount_) external
```

| Name             | Description                             |
| ---------------- | --------------------------------------- |
| `builderPoolId_` | ID of the builder pool to deposit into. |
| `amount_`        | Amount of MOR to deposit. Wei.          |

### withdraw

Withdraws tokens from a specific builder pool.

```solidity
function withdraw(bytes32 builderPoolId_, uint256 amount_) external
```

| Name             | Description                                                                     |
| ---------------- | ------------------------------------------------------------------------------- |
| `builderPoolId_` | Identifier of the builder pool from which tokens will be withdrawn              |
| `amount_`        | Amount of tokens to withdraw; will be limited by user balance if too high. Wei. |

### claim

Allows the builder pool admin to claim the pool’s accumulated MOR rewards.

```solidity
function claim(bytes32 builderPoolId_, address receiver_) external
```

| Name             | Description                                                        |
| ---------------- | ------------------------------------------------------------------ |
| `builderPoolId_` | Identifier of the builder pool from which tokens will be withdrawn |
| `receiver_`      | Address to receive the claimed MOR rewards                         |

## Read functions

### getNotDistributedRewards<br>

Returns the total unclaimed MOR rewards stored in the BuildersTreasury.

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

### getCurrentUserMultiplier

Returns the reward multiplier based on the user’s lock period for a pool.

```solidity
function getCurrentUserMultiplier(
  bytes32 builderPoolId_,
  address user_
) public view returns (uint256)
```

| Name             | Description                                                        |
| ---------------- | ------------------------------------------------------------------ |
| `builderPoolId_` | Identifier of the builder pool from which tokens will be withdrawn |
| `user_`          | User address whose multiplier is being calculated                  |

### getCurrentBuilderReward

Returns the current calculated reward for a builder pool.

```solidity
function getCurrentBuilderReward(
  bytes32 builderPoolId_
) external view returns (uint256)
```

| Name             | Description                                                        |
| ---------------- | ------------------------------------------------------------------ |
| `builderPoolId_` | Identifier of the builder pool from which tokens will be withdrawn |

### getLockPeriodMultiplier

Returns the multiplier for rewards based on a lock period.

```solidity
function getLockPeriodMultiplier(
  uint128 lockStart_,
  uint128 lockEnd_
) public pure returns (uint256)
```

| Name         | Description                                 |
| ------------ | ------------------------------------------- |
| `lockStart_` | Timestamp in seconds when the lock started. |
| `lockEnd_`   | Timestamp in seconds when the lock ends.    |

### getPoolId

Computes the unique ID of a builder pool based on its name.

```solidity
function getPoolId(string memory builderPoolName_) public pure returns (bytes32)
```

| Name               | Description              |
| ------------------ | ------------------------ |
| `builderPoolName_` | Name of the builder pool |

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IBuilders`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```


# BuildersTreasury

## Overview

The `BuildersTreasury` contract serves as a dedicated storage vault and distribution mechanism for builder rewards in the Morpheus protocol. It is tightly integrated with the `Builders` contract and acts as the reward source when builders (administrators of pools) claim their share of MOR tokens.

The treasury holds the reward token (typically MOR) and is the only contract authorized to send out rewards to builder pool administrators. It tracks the total distributed rewards to ensure correct accounting.

To function correctly, the Morpheus protocol administrators must ensure that this contract is regularly and sufficiently funded. This is critical for the accurate calculation and fair distribution of rewards, since the reward rate and availability are derived based on the current token balance in the treasury.

### Key Features

1. Reward source: acts as the source of truth and distribution for builder rewards in the protocol.
2. Access controlled: only the `Builders` contract can trigger reward transfers.
3. Reward accounting: tracks the total amount of rewards that have been distributed.
4. Protocol-funded: must be funded by Morpheus protocol operators on L1 (e.g., Ethereum) to ensure proper cross-chain reward emission calculations.

## Storage

### rewardToken

Holds the address of the MOR token used as the reward currency.

```solidity
address public rewardToken;
```

### builders

Stores the address of the authorized `Builders` contract that can distribute rewards.

```solidity
address public builders;
```

### distributedRewards

Tracks the total amount of rewards that have been distributed through this treasury.

```solidity
uint256 public distributedRewards;
```

## Functions for the contract owner

### BuildersTreasury\_init

Initializes the treasury contract with the reward token and  `Builders` contract.

```solidity
function BuildersTreasury_init(
  address rewardToken_,
  address builders_
) external initializer;
```

| Name           | Description                                                   |
| -------------- | ------------------------------------------------------------- |
| `rewardToken_` | Address of the MOR token used for rewards                     |
| `builders_`    | Address of the Builders contract authorized to manage rewards |

### setBuilders

Updates the address of the `Builders` contract.

```solidity
function setBuilders(address builders_) public onlyOwner
```

| Name        | Description                                       |
| ----------- | ------------------------------------------------- |
| `builders_` | Address of the new Builders contract to authorize |

## Functions for the Builders contract

### sendRewards

Transfers reward tokens to a specified receiver. Callable only by the Builders contract.

```solidity
function sendRewards(address receiver_, uint256 amount_) external onlyBuilders
```

| Name        | Description                               |
| ----------- | ----------------------------------------- |
| `receiver_` | Address of the user receiving the rewards |
| `amount_`   | Amount of reward tokens to transfer. Wei. |

## Read functions

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IBuildersTreasury`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```

### getAllRewards

Returns the total rewards managed by the treasury, including both distributed and undistributed tokens.

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

***

***


# FeeConfig

## Overview

The `FeeConfig` contract is a configuration module used within the protocol to manage and enforce protocol-level fees. It enables fine-grained control over fee application logic across different operations and protocol participants.

This contract is deployed on-chain and is designed to be upgradeable. It provides both default and customizable fee structures, allowing the protocol to charge fees for specific actions (such as withdrawals or reward claims) and route them to a designated treasury address.

## Key Features

1. Precision-based fee system: all fees are calculated using a precision constant (`PRECISION`) equal to 10<sup>25</sup>, which represents 100%. For example, `0.05*10^25` is equivalent to 5%.
2. Default and custom fees: allows setting a global base fee, operation-specific base fees, sender-specific custom fees, and operation-specific custom fees per sender.
3. Treasury routing: all collected fees are directed to a treasury address, which can be updated by the protocol owner.
4. Access control: only the contract owner (protocol administrator) can set or update fee configurations, ensuring controlled and secure modifications.

## Write functions

### FeeConfig\_init

Initializes the contract with essential parameters and configuration contracts. This function must be called once after deployment.

```solidity
function FeeConfig_init(
  address treasury_,
  uint256 baseFee_
) external initializer
```

| Name        | Description                                                                     |
| ----------- | ------------------------------------------------------------------------------- |
| `treasury_` | Address of the new treasury.                                                    |
| `baseFee_`  | The base fee value (must be less than PRECISION). Where 100% = 10<sup>25.</sup> |

### setTreasury

Updates the treasury address.

```solidity
function setTreasury(address treasury_) public onlyOwner
```

| Name        | Description                  |
| ----------- | ---------------------------- |
| `treasury_` | Address of the new treasury. |

## Set and receive base (default) fee for the caller

### setBaseFee

Sets the global base (default) fee for all callers. Only for the contract owner.

```solidity
function setBaseFee(uint256 baseFee_) public onlyOwner
```

| Name       | Description                                                                     |
| ---------- | ------------------------------------------------------------------------------- |
| `baseFee_` | The base fee value (must be less than PRECISION). Where 100% = 10<sup>25.</sup> |

### setFee

Sets the fee for the specific callers. Only for the contract owner.

```solidity
function setFee(address sender_, uint256 fee_) external onlyOwner
```

| Name      | Description                                                                     |
| --------- | ------------------------------------------------------------------------------- |
| `sender_` | The address for which to query fee.                                             |
| `fee_`    | The base fee value (must be less than PRECISION). Where 100% = 10<sup>25.</sup> |

### getFeeAndTreasury

Returns the fee for the caller or base fee (if caller fee isn't set), treasury address for a sender (contract).

```solidity
function getFeeAndTreasury(address sender_) external view returns (uint256, address)
```

| Name      | Description                         |
| --------- | ----------------------------------- |
| `sender_` | The address for which to query fee. |

## Set and receive operation fee for the caller

### setBaseFeeForOperation

Sets the base fee for a specific operation across the protocol. Only for the contract owner.

```solidity
function setBaseFeeForOperation(
  bytes32 operation_, 
  uint256 baseFeeForOperation_
) public onlyOwner
```

| Name                   | Description                                                                                  |
| ---------------------- | -------------------------------------------------------------------------------------------- |
| `operation_`           | Operation identifier.                                                                        |
| `baseFeeForOperation_` | The base fee for this operation (must be less than PRECISION). Where 100% = 10<sup>25.</sup> |

### setFeeForOperation

Sets the fee for a specific operation across the protocol for the specific caller. Only for the contract owner.

```solidity
function setFeeForOperation(
   address sender_, 
   bytes32 operation_, 
   uint256 fee_
) external onlyOwner
```

| Name                   | Description                                                                                 |
| ---------------------- | ------------------------------------------------------------------------------------------- |
| `operation_`           | Operation identifier.                                                                       |
| `baseFeeForOperation_` | The base fee for this operation (must be less than PRECISION). Where 100% = 10<sup>25</sup> |
| `sender_`              | The address for which to query fee.                                                         |

### discardCustomFee

Removes custom fee override for an operation for a specific caller.

```solidity
function discardCustomFee(
  address sender_, 
  bytes32 operation_
) external onlyOwner
```

| Name         | Description                                            |
| ------------ | ------------------------------------------------------ |
| `sender_`    | Address for which the custom fee is being discarded    |
| `operation_` | Operation identifier (e.g., `"claim"` or `"withdraw"`) |

### getFeeAndTreasuryForOperation

Returns the fee for a specific operation or base fee for a specific operation (if fee for a specific operation isn't set) and treasury address.

```solidity
function getFeeAndTreasuryForOperation(
  address sender_,
  bytes32 operation_
) external view returns (uint256, address)
```

| Name         | Description                                                  |
| ------------ | ------------------------------------------------------------ |
| `sender_`    | Address requesting the operation                             |
| `operation_` | Operation for which to retrieve the fee and treasury address |

## Read functions

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IFeeConfig`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```


# Get started


# Create the builder pool

## Pool creation

In the protocol, any user can create a builder pool by calling the `createBuilderPool` function. During creation, the user must specify a unique project name that will be used to generate the pool’s identifier using `keccak256`. Additionally, the creator must provide the builder’s address (the admin of the pool), who will be responsible for managing it. The builder must also define key parameters: the start time of the pool (`poolStart`), the withdrawal lock period after deposit (`withdrawLockPeriodAfterDeposit`), the reward claim unlock time (`claimLockEnd`), and the minimum allowed deposit amount (`minimalDeposit`). All of these parameters are validated by the contract before being accepted.

## Pool params

Each field in the `BuilderPool` struct plays a crucial role in defining the behavior of the pool. The `name` is the project label, used both for user identification and as the input for generating the unique pool ID.&#x20;

The `admin` field is the builder’s address, responsible for performing reward claims and pool management.&#x20;

The `poolStart` defines the timestamp from which users can begin depositing; any deposits made before this time will be rejected.&#x20;

`withdrawLockPeriodAfterDeposit` specifies the minimum time (in seconds) that must elapse after a user deposits before they are allowed to withdraw their tokens. This helps maintain deposit stability.

The `claimLockEnd` field defines when the `admin` can start claiming rewards and apply lock multiplier for all stakes until this timestamp.

&#x20;The `minimalDeposit` parameter ensures that any deposit (or remaining balance after a partial withdrawal) must meet or exceed a minimum threshold unless the user is fully withdrawing.

## Pool edit

Editing an existing pool is allowed only until the pool’s start time (`poolStart`). Only the builder (admin) who created the pool can perform edits. The `editBuilderPool` function accepts the same struct as the creation call, allowing modification of lock periods and start time. However, the new `poolStart` must not be earlier than the previously set one — this prevents time-based manipulation or rollback of the pool’s launch.

## Pool ID

The pool receives a unique `builderPoolId` derived from the project name using the following Solidity expression:

```solidity
bytes32 builderPoolId = keccak256(abi.encodePacked(builderPool.name));
```

This ID is then used in all pool-related operations including deposits, withdrawals, reward claiming, and internal data storage for builder configuration, user stakes, and reward accounting.


# Guides

This section contains detailed technical guides covering all aspects of protocol interaction.

Each guide focuses on a specific feature, explaining what it does, how it works, what parameters it accepts, and how to use it correctly.

If you’re already familiar with the protocol architecture, use these guides as a technical reference.&#x20;

{% hint style="info" %}
This section is currently under development.&#x20;
{% endhint %}


# Reward distribution

The reward distribution mechanism in the Builders protocol ensures that MOR tokens are fairly allocated among builder pools and their participants based on their contributions, with internal logic designed for efficiency and scalability.

## Overview

MOR rewards are not distributed automatically based on a predefined curve or emission schedule. Instead, rewards are manually supplied by the Morpheus multisig to the `BuildersTreasury` contract. Once deposited and stake, claim or withdraw transaction executed after the deposit, the system calculates and distributes rewards proportionally across all builder pools based on each pool’s virtual stake. Within each pool, the rewards are further divided among users.

Such an approach ensures that only the tokens actually available are distributed. The more frequently the treasury is replenished, the fairer the distribution will be among the subnets.

## Reward accumulation

When MOR tokens are deposited into the `BuildersTreasury`, the contract holds these tokens until a builder (admin of a pool) manually triggers a reward claim for their pool via the claim function. The claim function can only be called after a specified `claimLockEnd` time and only by the admin of the respective pool.

## Reward calculation formula

Pool rewards are calculated lazily — that is, only when a staker interacts with the contract (e.g., stake, withdraw, or claim), rather than updating every user on each pool. The calculation is performed using the following logic:

```solidity
uint256 poolReward = pendingRewards + virtualStake * (totalRewardCoefficient - pooluserRewardCoefficient);
```

* `pendingRewards` - rewards that were calculated after the stake or withdrawal — that is, after the pool’s share was modified.
* `virtualStake`  - the pool’s current stake after applying multipliers.
* `totalRewardCoefficient` - the current accumulated MOR per unit of virtual stake across the all pools.
* `pooluserRewardCoefficient` - the coefficient stored at the time of the last interaction in the pool.

The `totalRewardCoefficient` is updated globally when new rewards are distributed. It is calculated as:

```solidity
uint256 totalRewardCoefficient += distributedRewards / totalVirtualStake;
```

* `distributedRewards` - is the amount of MOR tokens allocated to the pool during distribution.
* `totalVirtualStake` - is the sum of all users’ virtual stake (after applying lock/referral multipliers) at the time of distribution.

This model allows each user’s reward to be efficiently and fairly computed based on the delta in the coefficient since their last update.

## Virtual stake and multipliers

Each user’s deposit is enhanced with a multiplier derived from their lock period (configured per pool).&#x20;

The total virtual stake of a pool is the sum of all users’ virtual stakes and determines the share of rewards that pool receives.


# v4 Protocol

Protocol v4 is a redesigned staking and reward distribution system built around the concept of Subnets. Each Subnet represents a distinct staking pool that users can join by depositing MOR tokens. The administrator of a Subnet can later claim MOR rewards proportionally to the total staked amount in that Subnet relative to the global network. The rewards are calculated in real time based on a global emission curve, which simulates MOR token distribution over time for the Builders bucket. Unlike earlier versions that relied on manual reward injections, v4 ensures continuous and fair distribution as long as the `BuildersTreasuryV2` contract holds sufficient MOR balance.

Subnet identifiers now incorporate the blockchain’s chain ID alongside the Subnet name, enabling Subnets with identical names to exist across multiple networks. Each Subnet also has its own metadata and allows specifying a separate claim administrator who is authorized to collect rewards on its behalf.

###


# Contracts

## Protocol architecture

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

## Core contracts

### BuildersV4

The `BuildersV4` contract governs the protocol’s core logic and state. It facilitates the creation and configuration of Subnets, user staking and withdrawal operations, and the dynamic reward distribution process.

A user can create a new Subnet by specifying parameters such as the administrator, claim administrator, minimum deposit... If a creation fee is configured, it is collected and forwarded to the appropriate treasury address via the `FeeConfig` contract.

Users may deposit MOR tokens into a Subnet, increasing its total stake and share in the global reward pool. Withdrawals are subject to a lock period defined per Subnet, and users must either maintain the minimum required deposit or fully exit their stake. Upon deposit, withdrawal, or reward claim, the contract recalculates reward allocations using the current emission rate provided by the `RewardPool` contract. This emission rate is scaled by the “network share” parameter to determine the portion allocated to Builders in the specific chain.

The administrator or claim administrator of a Subnet can trigger a claim, transferring accrued MOR rewards to a specified recipient address. Any applicable fee is deducted and transferred to the treasury. All Subnet and global statistics are updated with each operation to ensure accurate state tracking.

### BuildersTreasuryV2

`BuildersTreasuryV2` holds MOR tokens for distribution to Subnets. It receives reward claims initiated by the `BuildersV4` contract and securely transfers tokens to recipients. The treasury also tracks the total amount of claimed rewards.

Only the `BuildersV4` contract is authorized to execute reward payouts. The owner retains the ability to change the `BuildersV4` address and manually withdraw MOR tokens when needed, for purposes such as migration or administrative recovery.

### [RewardPool](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/rewardpool)

See the documentation for this contract [here](/smart-contracts/documentation/distribution-protocol/v7-protocol/contracts/rewardpool).

### [Fee config](/smart-contracts/documentation/builders-protocol/v2-protocol/contracts/feeconfig)

See the documentation for this contract [here](/smart-contracts/documentation/builders-protocol/v2-protocol/contracts/feeconfig).

## Periphery

### OpenZeppelin

Used extensively across contracts to support secure access control and upgradeability:

* `OwnableUpgradeable` – enables ownership access control.
* `UUPSUpgradeable` – facilitates contract upgradeability via the UUPS (Universal Upgradeable Proxy Standard) pattern.

Links:

* <https://docs.openzeppelin.com/contracts/4.x/access-control>
* <https://docs.openzeppelin.com/contracts/4.x/api/proxy>


# BuildersV4

## Overview

The `BuildersV4` protocol is an on-chain coordination layer designed for distributing MOR token rewards to subnet builders in a scalable and fair manner. It allows anyone to create a Subnet with specific staking parameters and enables users to stake MOR tokens under a particular Subnet. Rewards are calculated globally and distributed to Subnets based on their effective contribution, determined through staked amounts.

Each Subnet is identified by a unique ID derived from its name and the chain ID, allowing for identical Subnet names across multiple blockchains (v1 and v2 Subnets will have previous ID). Subnet builders (admins) and subnet claim admin are the only ones authorized to claim MOR rewards for their Subnets, while users’ rewards are handled off-chain by the builders. The reward calculation is powered by an external emission curve (`RewardPool`) and uses a rate model to determine distribution over time.

Unlike previous versions, v4 removes virtual deposits and multipliers, simplifying staking logic and removing dependency on the claim lock end. Additionally, the system introduces a `networkShare` parameter to control how much of the `RewardPool` output flows to Builders overall.

## Key Features

1. Subnet creation and configuration: anyone can create a pool with custom parameters; the builder (admin) is assigned at creation.
2. User staking: users stake tokens into any subnet.
3. Subnet-controlled reward claiming: only the Subnet admin or Subnet claim admin can claim the MOR rewards, enabling flexible distribution outside the contract scope.
4. Reward calculation: uses a dynamic rate updated with each user action and proportional to the protocol-wide deposits.
5. Fee system: integrated with `FeeConfig` for applying customizable claim and creation fees.
6. Upgradeable and permissioned: built with UUPS and Ownable patterns for controlled upgrades and ownership-based access.

## Storage

### feeConfig

Address of the `FeeConfig` contract used to calculate protocol fees.

```solidity
address public feeConfig;
```

### buildersTreasury

Address of the `BuildersTreasury` contract which stores and distributes reward tokens.

```solidity
address public buildersTreasury;
```

### depositToken

Address of the MOR token users deposit into Subnets.

```solidity
address public depositToken;
```

### unusedStorage1\_V4Update (old editPoolDeadline)

~~The time window (in seconds) before the pool starts, during which pool parameters can still be edited by the pool admin.~~ Deprecated in v4.

```solidity
uint128 public editPoolDeadline;
```

### minimalWithdrawLockPeriod

Minimum duration (in seconds) after a deposit during which withdrawals are locked.

```solidity
uint256 public minimalWithdrawLockPeriod;
```

### allSubnetsData (old totalPoolData)

Aggregated data for all Subnets pools in the system.

```solidity
AllSubnetsData public allSubnetsData;

struct TotalPoolData {
  uint256 distributedRewards;
  uint256 rate;
  uint256 totalDeposited;
  uint256 totalVirtualDeposited;
}
```

| Name                    | Description                                                               |
| ----------------------- | ------------------------------------------------------------------------- |
| `distributedRewards`    | Total amount of rewards distributed across all pools. Wei.                |
| `rate`                  | The current reward rate                                                   |
| `totalDeposited`        | Total tokens deposited without applying any multiplier. Wei.              |
| `totalVirtualDeposited` | Total tokens deposited with multiplier (used in reward calculations). Wei |

### subnets (old builderPools)

Mapping of  `subnetID` to Subnet configuration.

```solidity
mapping(bytes32 subnetId => Subnet) public subnets;

struct Subnet {
  string name;
  address admin;
  uint128 unusedStorage1_V4Update;
  uint128 withdrawLockPeriodAfterDeposit;
  uint128 unusedStorage2_V4Update;
  uint256 minimalDeposit;
  address claimAdmin;
}

```

| Name                                         | Description                                                                                       |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `name`                                       | The name of the Subnet.                                                                           |
| `admin`                                      | The address of the Subnet administrator.                                                          |
| `unusedStorage1_V4Update (old poolStart)`    | ~~Timestamp when the pool becomes active.~~ Deprecated in v4.                                     |
| `withdrawLockPeriodAfterDeposit`             | Time period after deposit during which withdrawal is locked. Seconds.                             |
| `unusedStorage2_V4Update (old claimLockEnd)` | ~~Timestamp after which rewards can be claimed by the Subnets admin. Seconds.~~ Deprecated in v4. |
| `minimalDeposit`                             | Minimum amount a user must deposit to participate. Wei.                                           |
| `claimAdmin`                                 | This address can claim the Subnet rewards against `admin`.                                        |

### subnetsData (old buildersPoolData)

Mapping of pool ID to the current dynamic pool state.

```solidity
mapping(bytes32 subnetId => SubnetData) public subnetsData;

struct SubnetData {
  uint128 unusedStorage1_V4Update;
  uint256 deposited;
  uint256 unusedStorage2_V4Update;
  uint256 rate;
  uint256 pendingRewards;
}
```

| Name                                             | Description                                                                                                            |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `unusedStorage1_V4Update (old lastDeposit)`      | ~~Timestamp in seconds of the last deposit into the pool.~~ Deprecated in v4.                                          |
| `deposited`                                      | Total amount deposited MOR. Wei.                                                                                       |
| `unusedStorage2_V4Update (old virtualDeposited)` | ~~Total amount deposited with multipliers applied. Wei.~~ Deprecated in v4.                                            |
| `rate`                                           | Current reward rate for the Subnet                                                                                     |
| `pendingRewards`                                 | Number of rewards accrued to the Subnet. Is not the final reward at a given time. Used for internal calculations. Wei. |

### usersData

Mapping of user address and pool ID to their user-specific data.

```solidity
mapping(address => mapping(bytes32 => UserData)) public usersData;

struct UserData {
  uint128 lastDeposit;
  uint128 unusedStorage1_V4Update;
  uint256 deposited;
  uint256 unusedStorage2_V4Update;
}
```

| Name                                             | Description                                                                       |
| ------------------------------------------------ | --------------------------------------------------------------------------------- |
| `lastDeposit`                                    | Timestamp in seconds of the user's last deposit.                                  |
| `unusedStorage1_V4Update ( old claimLockStart)`  | ~~Timestamp when the user activated the reward lock. Seconds~~. Deprecated in v4. |
| `deposited`                                      | Total tokens the user deposited (raw amount). Wei.                                |
| `unusedStorage2_V4Update (old virtualDeposited)` | ~~Tokens deposited by user with multiplier applied. Wei~~. Deprecated in v4.      |

### rewardPool

The address of the `RewardPool` contract address.

```solidity
address public rewardPool;
```

### subnetCreationFeeAmount

This value in wei is taken from the tx sender when the Subnet created.

```solidity
uint256 public subnetCreationFeeAmount;
```

### networkShare

The `networkShare` is the share of the network rewards that will be distributed to Subnets, e.g. `100% = 10^25`. If global reward curve return `X` amount of rewards, then all Subnets will \* receive `X * networkShare / 10^25`

```solidity
uint256 public networkShare;
```

### networkShareOwner

This address can change the `networkShare` value.

```solidity
address public networkShareOwner;
```

### subnetsMetadata

Contain the metadata about Subnets

```solidity
mapping(bytes32 subnetId => SubnetMetadata) public subnetsMetadata;

struct SubnetMetadata {
  string slug;
  string description;
  string website;
  string image;
}
```

| Name          | Description                    |
| ------------- | ------------------------------ |
| `slug`        | The Subnet slug string.        |
| `description` | The Subnet description string. |
| `website`     | The Subnet website string.     |
| `image`       | The Subnet image link.         |

### allSubnetsDataV4

The variable that stores all Subnets data, addition for `allSubnetsData`.

```solidity
AllSubnetsDataV4 public allSubnetsDataV4;

struct AllSubnetsDataV4 {
  uint256 distributedRewards;
  uint256 undistributedRewards;
  uint256 claimedRewards;
  uint128 lastUpdate;
}
```

| Name                   | Description                                                                           |
| ---------------------- | ------------------------------------------------------------------------------------- |
| `distributedRewards`   | The amount of rewards that calculated and virtually distributed between Subnets. Wei. |
| `undistributedRewards` | The amount of rewards that calculated and stored for the contract owner. Wei          |
| `claimedRewards`       | The total amount of claimed rewards. Wei.                                             |
| `lastUpdate`           | The `AllSubnetsData.rate` last update timestamp.                                      |

### Fee oprations

The lables for fee operations, uses for fee and treasury receiving in the `FeeConfig` contract. `FEE_SUBNET_CREATE` uses only treasury address from the `FeeConfig` contract.

```solidity
// bytes32 private constant FEE_WITHDRAW_OPERATION = "withdraw";
bytes32 public constant FEE_CLAIM_OPERATION = "claim";
bytes32 public constant FEE_SUBNET_CREATE = "buildersV4.fee.subnet.create";
```

## Write functions for the contract owner

### BuildersV4\_init

Initializes the contract with essential parameters and configuration contracts. This function must be called once after deployment.

```solidity
function BuildersV4_init(
  address depositToken_,
  address feeConfig_,
  address treasury_,
  address rewardPool_,
  address networkShareOwner_,
  uint256 minimalWithdrawLockPeriod_
) external initializer
```

| Name                         | Description                                                                          |
| ---------------------------- | ------------------------------------------------------------------------------------ |
| `depositToken_`              | Address of the token that users will deposit in builder pools. MOR token.            |
| `feeConfig_`                 | Address of the `FeeConfig` contract used to calculate protocol fees.                 |
| `treasury_`                  | Address of the `BuildersTreasuryV2` contract used to store and distribute rewards.   |
| `rewardPool_`                | Address of the `RewardPool` contract.                                                |
| `networkShareOwner_`         | The address wich can edit the `networkShare`.                                        |
| `minimalWithdrawLockPeriod_` | Minimum lock duration after deposit in seconds before users can withdraw staked MOR. |

### setFeeConfig

Sets the address of the `FeeConfig` contract.

```solidity
function setFeeConfig(address feeConfig_) public onlyOwner
```

| Name         | Description                                      |
| ------------ | ------------------------------------------------ |
| `feeConfig_` | Address of a contract that implements IFeeConfig |

### setBuildersTreasury

Sets the address of the `BuildersTreasuryV2` contract.

```solidity
function setBuildersTreasury(address buildersTreasury_) public onlyOwner
```

| Name                | Description                                             |
| ------------------- | ------------------------------------------------------- |
| `buildersTreasury_` | Address of a contract that implements IBuildersTreasury |

### setMinimalWithdrawLockPeriod

Sets the minimum lock period that must pass before a user can withdraw MOR after depositing.

```solidity
function setMinimalWithdrawLockPeriod(
  uint256 minimalWithdrawLockPeriod_
) public onlyOwner
```

| Name                         | Description                                                      |
| ---------------------------- | ---------------------------------------------------------------- |
| `minimalWithdrawLockPeriod_` | Minimum lock period (in seconds) after deposit before withdrawal |

### setRewardPool

Sets the address of the `RewardPool` contract.

```solidity
function setRewardPool(address rewardPool_) external onlyOwner;
```

| Name          | Description                                  |
| ------------- | -------------------------------------------- |
| `rewardPool_` | Address of the `RewardPool` contract to set. |

### setNetworkShareOwner

Sets the address that is authorized to change the networkShare value.

```solidity
function setNetworkShareOwner(address networkShareOwner_) external onlyOwner;
```

| Name                 | Description                                                      |
| -------------------- | ---------------------------------------------------------------- |
| `networkShareOwner_` | Address that will be allowed to update the `networkShare` value. |

### setNetworkShare

Sets the percentage of rewards allocated to all Subnets.

```solidity
function setNetworkShare(uint256 networkShare_) external onlyOwner;
```

| Name            | Description                                                            |
| --------------- | ---------------------------------------------------------------------- |
| `networkShare_` | Percentage value where 100% = 1e25. Only owner or `networkShareOwner`. |

### setSubnetCreationFeeAmount

Sets the fee amount (in MOR tokens) required to create a Subnet.

```solidity
function setSubnetCreationFeeAmount(
  uint256 subnetCreationFeeAmount_
) external onlyOwner;
```

| Name                       | Description        |
| -------------------------- | ------------------ |
| `subnetCreationFeeAmount_` | MOR amount in wei. |

## Write functions

### createBuilderPool

Creates a new Subnet with specific parameters. If `subnetCreationFee` set, it will be charged from the tx caller.

```solidity
function createSubnet(
  Subnet calldata subnet_,
  SubnetMetadata calldata metadata_
) external;
```

| Name        | Description                  |
| ----------- | ---------------------------- |
| `subnet_`   | The `Subnet` struct.         |
| `metadata_` | The `SubnetMetadata` struct. |

### editSubnet

Edits an existing Subnet's main configuration. The caller should be the Subnet admin.

```solidity
function editSubnet(
  bytes32 subnetId_,
  Subnet calldata newSubnet_
) external onlySubnetOwner(subnetId_)
```

| Name         | Description          |
| ------------ | -------------------- |
| `subnetId_`  | ID of the Subnet.    |
| `newSubnet_` | The `Subnet` struct. |

### editSubnet

Edits an existing Subnet's metadata configuration. The caller should be the Subnet admin.

```solidity
function editSubnetMetadata(
  bytes32 subnetId_,
  SubnetMetadata calldata metadata_
) public onlySubnetOwner(subnetId_)
```

| Name        | Description                  |
| ----------- | ---------------------------- |
| `subnetId_` | ID of the Subnet.            |
| `metadata_` | The `SubnetMetadata` struct. |

### deposit

Allows a user to deposit tokens into a specific Subnet.

```solidity
function deposit(bytes32 subnetId_, uint256 amount_) external
```

| Name        | Description                       |
| ----------- | --------------------------------- |
| `subnetId_` | ID of the Subnet.                 |
| `amount_`   | Amount of tokens to deposit. Wei. |

### withdraw

Allows a user to withdraws tokens from a specific Subnet.

```solidity
function withdraw(bytes32 subnetId_, uint256 amount_) external
```

| Name        | Description                        |
| ----------- | ---------------------------------- |
| `subnetId_` | ID of the Subnet.                  |
| `amount_`   | Amount of tokens to withdraw. Wei. |

### claim

Allows the Subnet admin or Subnet claim admin to claim the accumulated MOR rewards.

```solidity
function claim(bytes32 subnetId_, address receiver_) external
```

| Name        | Description                                |
| ----------- | ------------------------------------------ |
| `subnetId_` | ID of the Subnet.                          |
| `receiver_` | Address to receive the claimed MOR rewards |

## Read functions

### getCurrentSubnetsRewards<br>

The function calculates the potential claim reward amount for **ALL** Subnets at the current moment in time, based on the current contract parameters. It estimates the unclaimed rewards that would be distributed if a claim were made now.

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

### getCurrentSubnetRewards

The function calculates the potential claim reward amount for the **SPECIFIC** Subnet at the current moment in time, based on the current contract parameters. It estimates the unclaimed rewards that would be distributed if a claim were made now.

```solidity
function getCurrentSubnetRewards(
  bytes32 subnetId_
) external view returns (uint256)
```

| Name        | Description       |
| ----------- | ----------------- |
| `subnetId_` | ID of the Subnet. |

### getSubnetId

Computes the unique ID of a Subnet based on its name and chain ID.

```solidity
function getSubnetId(string memory subnetName_) public view returns (bytes32)
```

| Name          | Description        |
| ------------- | ------------------ |
| `subnetName_` | Name of the Subnet |

### getSubnetIdOld

Computes the unique ID of a Subnet based on its name. Subnets created in the v1 and v2 used this ID.

```solidity
function getSubnetIdOld(string memory subnetName_) public view returns (bytes32)
```

| Name          | Description        |
| ------------- | ------------------ |
| `subnetName_` | Name of the Subnet |

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IBuildersV2`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```

### version

Returns the current version of the contract.

```solidity
function version() external pure returns (uint256
```


# BuildersTreasuryV2

## Overview

The `BuildersTreasuryV2` contract serves as a dedicated storage vault and distribution mechanism for builder rewards in the protocol. It is tightly integrated with the `BuildersV4` contract and acts as the reward source when the Subnet admin or claim admin claim their share of MOR tokens.

The treasury holds the reward token (MOR) and is the only contract authorized to send out rewards. It tracks the total distributed rewards (claimed amount).

To function correctly, the protocol administrator (owner) must ensure that this contract is regularly and sufficiently funded.&#x20;

### Key Features

1. Reward source: acts as the source of truth and distribution for builder rewards in the protocol.
2. Access controlled: only the `BuildersV4` contract can trigger reward transfers.
3. Reward accounting: tracks the total amount of rewards that have been distributed.
4. Protocol-funded: must be funded by Morpheus protocol operators on L1 (e.g., Ethereum) to ensure proper cross-chain reward payments.

## Storage

### rewardToken

Holds the address of the MOR token used as the reward currency.

```solidity
address public rewardToken;
```

### builders

Stores the address of the authorized `BuildersV4` contract that can distribute rewards.

```solidity
address public builders;
```

### distributedRewards

Tracks the total amount of rewards that have been distributed through this treasury.

```solidity
uint256 public distributedRewards;
```

## Functions for the contract owner

### BuildersTreasuryV2\_init

Initializes the treasury contract with the reward token and  `BuildersV2` contract.

```solidity
function BuildersTreasuryV2_init(
  address rewardToken_,
) external initializer;
```

| Name           | Description                               |
| -------------- | ----------------------------------------- |
| `rewardToken_` | Address of the MOR token used for rewards |

### setBuilders

Updates the address of the `BuildersV4` contract.

```solidity
function setBuilders(address builders_) public onlyOwner
```

| Name        | Description                                           |
| ----------- | ----------------------------------------------------- |
| `builders_` | Address of the new `BuildersV4` contract to authorize |

### withdraw

The function to withdraw `rewardToken` from the contract.

```solidity
 function withdraw(address receiver_, uint256 amount_) external onlyOwner;
```

| Name        | Description                               |
| ----------- | ----------------------------------------- |
| `receiver_` | Address of the user receiving the rewards |
| `amount_`   | Amount of tokens to transfer. Wei.        |

## Functions for the BuildersV4 contract

### sendRewards

Transfers reward tokens to a specified receiver. Callable only by the Builders contract.

```solidity
function sendRewards(address receiver_, uint256 amount_) external onlyBuilders
```

| Name        | Description                               |
| ----------- | ----------------------------------------- |
| `receiver_` | Address of the user receiving the rewards |
| `amount_`   | Amount of tokens to transfer. Wei.        |

## Read functions

### supportsInterface

Used for interface detection (ERC165). Returns true if the contract supports a specific `interfaceId_`. Supports `IBuildersTreasuryV2`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```

### version

Returns the current version of the contract.

```solidity
function version() external pure returns (uint256
```


# Guides

This section contains detailed technical guides covering all aspects of protocol interaction.

Each guide focuses on a specific feature, explaining what it does, how it works, what parameters it accepts, and how to use it correctly.

If you’re already familiar with the protocol architecture, use these guides as a technical reference.&#x20;

{% hint style="info" %}
This section is currently under development.&#x20;
{% endhint %}


# Migration from v2 to v4

### Deployed contracts

#### Base

<table><thead><tr><th width="283.109375">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>BuildersV4 (impl)</code> </td><td><a href="https://basescan.org/address/0x18FAEf315b40A6D9cf49628f1133B1Aa507513B0">0x18FAEf315b40A6D9cf49628f1133B1Aa507513B0</a></td></tr><tr><td><code>BuildersTreasuryV2 (impl)</code> </td><td><a href="https://basescan.org/address/0xe71eB0b69bbD4207e2cB10DF929d1311D2ad57e5">0xe71eB0b69bbD4207e2cB10DF929d1311D2ad57e5</a></td></tr><tr><td><code>RewardPool</code></td><td><a href="https://basescan.org/address/0xDC99a8596e395E52aba2BD08C623E1e428Dc3980">0xDC99a8596e395E52aba2BD08C623E1e428Dc3980</a></td></tr></tbody></table>

#### Arbitrum

<table><thead><tr><th width="283.109375">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>BuildersV4 (impl)</code> </td><td><a href="https://arbiscan.io/address/0x6cCE082851Add4c535352f596662521B4De4750E">0x6cCE082851Add4c535352f596662521B4De4750E</a></td></tr><tr><td><code>BuildersTreasuryV2 (impl)</code> </td><td><a href="https://arbiscan.io/address/0x031075f7A853E8d4BF0B525466A78374aFAA9308">0x031075f7A853E8d4BF0B525466A78374aFAA9308</a></td></tr><tr><td><code>RewardPool</code></td><td><a href="https://arbiscan.io/address/0x281bc6F84952Abe53F6921dcD76c879d3C4b6375">0x281bc6F84952Abe53F6921dcD76c879d3C4b6375</a></td></tr></tbody></table>

### Upgrade the `BuildersTreasury` to `BuildersTreasuryV2`

Use the UUPS upgrade pattern to update the `BuildersTreasury` proxy contract to the new `BuildersTreasuryV2` implementation with `upgradeTo()` function. Once upgraded, perform the necessary configuration steps below.

See the `BuildersTreasuryV2 (impl)` address on the deployed section.

### Upgrade the `BuildersV2` to `BuildersV4`

Use the UUPS upgrade pattern to update the `BuildersV2` proxy contract to the new `BuildersV4` implementation with `upgradeTo()` function. Once upgraded, perform the necessary configuration steps below.

See the `BuildersV4 (impl)` address on the deployed section.

### Set the `RewardPool` address

Call `setRewardPool()` on the `BuildersV4` contract to assign the newly deployed `RewardPool` contract.

See the `RewardPool` address on the deployed section.

### Set the `networkShare`

Call `setNetworkShare()` to configure the percentage of MOR rewards that should be distributed to Subnets. This value is specified in precision units, where 1 \* 10<sup>25</sup> = 100%, 0.2 \* 10<sup>25</sup> = 20%...

The sum of shares for all networks must be 100% or 10<sup>25</sup>.

### Set the `networkShareOwner` (optional)

Call `setNetworkShareOwner()` to assign the address that is allowed to update the `networkShare` value in the future. This allows dynamic tuning of rewards per network if needed.

### Configure fee (optional)

If you want to add a fee for creating subnets:

* Сonfigure the `FeeConfig` contract by calling `setFeeForOperation(address sender_, bytes32 operation_, uint256 fee_)` where:
  * `sender_` : `BuildersV4` contract address (the same as `BuildersV2`);
  * `operation_` : `0x6275696c6465727356342e6665652e7375626e65742e63726561746500000000` ;
  * `fee_` : any value less then 10<sup>25</sup>;
* Then call `setSubnetCreationFeeAmount` on the `BuildersV4` contract with the fee amount in wei.

If you want to add a fee for claim operation

* Сonfigure the `FeeConfig` contract by calling `setFeeForOperation(address sender_, bytes32 operation_, uint256 fee_)` where:
  * `sender_` : `BuildersV4` contract address (the same as `BuildersV2`);
  * `operation_` : `0x636c61696d000000000000000000000000000000000000000000000000000000` ;
  * `fee_` : value, where 1 \* 10<sup>25</sup> = 100%, 0.2 \* 10<sup>25</sup> = 20%..

### Fund the Treasury

Transfer the required amount of MOR tokens to the `BuildersTreasuryV2` contract. This contract will be responsible for sending rewards to subnet admins during the `claim()` process.


# Required MOR balance on the treasury contract

## For all Subnets

Starting from v4, Subnet rewards are continuously accrued based on an emissions curve stored in the `RewardPool` contract. The emission is global and applies across all networks, with a network-specific multiplier determining how much reward is allocated per chain.

To ensure the system can fulfill all reward obligations at any time, the `BuildersTreasuryV2` contract must hold enough MOR tokens to cover all distributed but unclaimed rewards.

Call the function [`getCurrentSubnetsRewards()`](/smart-contracts/documentation/builders-protocol/v4-protocol/contracts/buildersv4#getcurrentsubnetsrewards). This function returns the total amount of rewards allocated to Subnets but not yet claimed. It accounts for the global reward rate and the time since the last update. This is the minimum MOR token amount that must be present on the treasury contract to pay out Subnet rewards at this point in time.

## For specific Subnet

To calculate the unclaimed rewards for a specific subnet, use [getCurrentSubnetRewards()](/smart-contracts/documentation/builders-protocol/v4-protocol/contracts/buildersv4#getcurrentsubnetrewards). This function computes the reward for the given Subnet, based on the updated global rate and the Subnet’s deposited amount.


# Changelog

From v2 to v4

## BuildersV2 -> BuildersV4

### Storage

Some of the storage variables have been deprecated to `unusedStorage...` to maintain upgradeability alignment:

* `editPoolDeadline` renamed to `unusedStorage1_V4Update` and deprecated. The functionality of time-limited Subnet editing has been removed.

Some variables were renamed to improve the clarity of the contract logic:

* `totalPoolData` renamed to `allSubnetsData` .
* `builderPools` renamed to `subnets` .
* `buildersPoolData` renamed to `subnetsData` .
* struct `BuilderPool` renamed to `Subnet` .
* struct `BuilderPoolData` renamed to `SubnetData` .
* struct `TotalPoolData` renamed to `AllSubnetsData` .

Introduced new [storage](/smart-contracts/documentation/builders-protocol/v4-protocol/contracts/buildersv4#storage) fields such as:

* `rewardPool`.
* `subnetCreationFeeAmount`.
* `networkShare`.
* `networkShareOwner`.
* `subnetsMetadata`.
* `allSubnetsDataV4`.
* `FEE_SUBNET_CREATE`.

Some existing structures stopped using certain functionality (see [here](/smart-contracts/documentation/builders-protocol/v4-protocol/contracts/buildersv4#storage)), so some fields were renamed to `unusedStorage..` accordingly to reflect their updated purpose.

### Functions

Some functions have been removed because their functionality is no longer needed or does not meet requirements.

#### Deprecated functions

* `setEditPoolDeadline(...)`
* `getNotDistributedRewards(...)`
* `getCurrentUserMultiplier(...)`
* `getLockPeriodMultiplier(...)`

#### Signature changed functions

* `createBuilderPool(BuilderPool calldata builderPool_)` -> `createSubnet(Subnet calldata subnet_, SubnetMetadata calldata metadata_)`
* `editBuilderPool(BuilderPool calldata builderPool_)` -> `editSubnet(bytes32 subnetId_, Subnet calldata newSubnet_)`
* `getPoolId(string memory builderPoolName_)` -> `getSubnetId(string memory subnetName_)` or `getSubnetIdOld(string memory subnetName_)`
* `getCurrentBuilderReward(bytes32 builderPoolId_)` -> `getCurrentSubnetRewards(bytes32 subnetId_)`

### BuilderPool -> Subnet changes

In the new version of the protocol, the logic of Subnets has been simplified. The claim lock and subnet start time are no longer used — once a Subnet is created, users can immediately start depositing tokens without any time restrictions.&#x20;

Additionally, support has been added for an extra address (claimAdmin) that can claim rewards on behalf of the main subnet admin. See `Subnet.claimAdmin`.

Subnets now support metadata, allowing descriptive or auxiliary information to be attached. See `SubnetMetadata` struct.

Editing is split into two parts: a user can update the main subnet configuration (`editSubnet()`) and its metadata (`editSubnetMetadata()`) independently. However, as before, the Subnet name cannot be changed after creation.

The Subnet ID format has also been updated: it is now calculated based on the blockchain’s chain ID and the Subnet name. This ensures uniqueness of names within each network. Existing subnets continue to use the legacy ID format to maintain backward compatibility.

```solidity
/**
 * @dev Get the Subnet ID by the `subnetName_` and the current `block.chainid`.
 * All Subnets in V4 will have new IDs.
 */
function getSubnetId(string memory subnetName_) public view returns (bytes32) {
  return keccak256(abi.encodePacked(block.chainid, subnetName_));
}

/**
 * @dev Get the Subnet ID by the `subnetName_`. Wee keep this function for backward
 * compatibility.
 */
function getSubnetIdOld(string memory subnetName_) public pure returns (bytes32) {
  return keccak256(abi.encodePacked(subnetName_));
}
```

### Reward Distribution Mechanism Update

The reward distribution logic has been redesigned. Rewards are now continuously distributed to subnets based on an emission curve stored in the `RewardPool` contract under a specific index - `3`. The `_getCurrentRate()` method has been refactored to accommodate this behavior.

Since the protocol operates in a multichain environment — where a single emission curve serves multiple networks — a `networkShare` multiplier has been introduced. This multiplier is applied to all rewards distributed on a particular network.

The multiplier can be set either by the protocol administrator or a designated trusted address, stored in variable `networkShareOwner` and assigned through function `setNetworkShareOwner()`. Its value must always be less than or equal to 1, and is expected to reflect the total stake volume within the respective network.

{% hint style="info" %}
The logic for calculating the `networkShare` multiplier is outside the scope of this change.
{% endhint %}

### Power Factor

Totally deprecated with related functionality.

## BuildersTreasury -> BuildersTreasuryV2

The contract has remained mostly unchanged. To improve security, the `SafeERC20` library was introduced. The `getAllRewards()` function was removed, as it is no longer required under the current architecture.

A new function `withdraw()` was added to allow the multisig (contract owner) to withdraw MOR tokens from the contract as needed. This provides greater flexibility for rewards management and simplifies contract maintenance.

## RewardPool

The new protocol architecture introduces the `RewardPool` contracts to support new business logic.

## Links

<https://github.com/MorpheusAIs/SmartContracts/pull/54>


# Deployed contracts

## Mainnet

### Arbitrum One

<table><thead><tr><th width="203.89453125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>BuildersV4</code></td><td><a href="https://arbiscan.io/address/0xC0eD68f163d44B6e9985F0041fDf6f67c6BCFF3f"><kbd>0xC0eD68f163d44B6e9985F0041fDf6f67c6BCFF3f</kbd></a></td></tr><tr><td><code>BuildersTreasuryV2</code></td><td><a href="https://arbiscan.io/address/0xCBE3d2c3AdE62cf7aa396e8cA93D2A8bff96E257"><kbd>0xCBE3d2c3AdE62cf7aa396e8cA93D2A8bff96E257</kbd></a></td></tr><tr><td><code>FeeConfig</code></td><td><a href="https://arbiscan.io/address/0xc03d87085E254695754a74D2CF76579e167Eb895"><kbd>0xc03d87085E254695754a74D2CF76579e167Eb895</kbd></a></td></tr><tr><td><code>RewardPool</code></td><td><a href="https://arbiscan.io/address/0x281bc6F84952Abe53F6921dcD76c879d3C4b6375"><kbd>0x281bc6F84952Abe53F6921dcD76c879d3C4b6375</kbd></a></td></tr></tbody></table>

### Base Mainnet

<table><thead><tr><th width="203.89453125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>BuildersV4</code></td><td><a href="https://basescan.org/address/0x42BB446eAE6dca7723a9eBdb81EA88aFe77eF4B9"><kbd>0x42BB446eAE6dca7723a9eBdb81EA88aFe77eF4B9</kbd></a></td></tr><tr><td><code>BuildersTreasuryV2</code></td><td><a href="https://basescan.org/address/0x9eba628581896ce086cb8f1A513ea6097A8FC561"><kbd>0x9eba628581896ce086cb8f1A513ea6097A8FC561</kbd></a></td></tr><tr><td><code>FeeConfig</code></td><td><a href="https://basescan.org/address/0x845FBB4B3e2207BF03087b8B94D2430AB11088eE"><kbd>0x845FBB4B3e2207BF03087b8B94D2430AB11088eE</kbd></a></td></tr><tr><td><code>RewardPool</code></td><td><a href="https://basescan.org/address/0xDC99a8596e395E52aba2BD08C623E1e428Dc3980"><kbd>0xDC99a8596e395E52aba2BD08C623E1e428Dc3980</kbd></a></td></tr></tbody></table>

#### Graph for the v4

{% embed url="<https://api.goldsky.com/api/public/project_cmgzm6igw009l5np264iw7obk/subgraphs/morpheus-mainnet-arbitrum-compatible/v0.0.1/gn>" %}

{% embed url="<https://api.goldsky.com/api/public/project_cmgzm6igw009l5np264iw7obk/subgraphs/morpheus-mainnet-base-compatible/v0.0.1/gn>" %}

## Testnet

### Arbitrum Sepolia

<table><thead><tr><th width="203.89453125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>BuildersV4</code></td><td><a href="https://sepolia.arbiscan.io/address/0x91507311283Dfd771797640dfDA7cEF3d8621ba4"><kbd>0x91507311283Dfd771797640dfDA7cEF3d8621ba4</kbd></a></td></tr><tr><td><code>BuildersTreasury</code></td><td><a href="https://sepolia.arbiscan.io/address/0x1C4b1025bf5b13e6CeD0dcf53f82ed01B5c27fB6"><kbd>0x1C4b1025bf5b13e6CeD0dcf53f82ed01B5c27fB6</kbd></a></td></tr><tr><td><code>FeeConfig</code></td><td><a href="https://sepolia.arbiscan.io/address/0x6F9ea6F9B81feEe17604F7878f1Db22134a3E56A"><kbd>0x6F9ea6F9B81feEe17604F7878f1Db22134a3E56A</kbd></a></td></tr></tbody></table>

#### Graph for the v4

{% embed url="<https://api.goldsky.com/api/public/project_cmh0hoqs10067w2p2dwmt5rao/subgraphs/morpheus-arbitrum-sepolia/v0.0.4/gn>" %}

### Base Sepolia

<table><thead><tr><th width="203.89453125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>BuildersV4</code></td><td><a href="https://sepolia.basescan.org/address/0x6C3401D71CEd4b4fEFD1033EA5F83e9B3E7e4381"><kbd>0x6C3401D71CEd4b4fEFD1033EA5F83e9B3E7e4381</kbd></a></td></tr><tr><td><code>BuildersTreasuryV2</code></td><td><a href="https://sepolia.basescan.org/address/0x05BfFa864b11e8Cd33367a4E95D75309b76434EB"><kbd>0x05BfFa864b11e8Cd33367a4E95D75309b76434EB</kbd></a></td></tr><tr><td><code>FeeConfig</code></td><td><a href="https://sepolia.basescan.org/address/0x926993cf1ffe3978500d95db591ac7a58d33c772"><kbd>0x926993cf1ffe3978500d95db591ac7a58d33c772</kbd></a></td></tr><tr><td><code>RewardPool</code></td><td><a href="https://sepolia.basescan.org/address/0x10777866547c53CBD69b02c5c76369d7e24e7b10"><kbd>0x10777866547c53CBD69b02c5c76369d7e24e7b10</kbd></a></td></tr></tbody></table>

#### Graph for the v4

{% embed url="<https://api.goldsky.com/api/public/project_cmh0hoqs10067w2p2dwmt5rao/subgraphs/morpheus-base-sepolia/v0.0.1/gn>" %}


# MOR OFT

The contract is the core implementation of the MOR token using LayerZero’s Omnichain Fungible Token (OFT) standard. It extends the traditional ERC20 token with cross-chain messaging capabilities, controlled minting, and token burning. The contract is designed to enable seamless use of the MOR token across multiple blockchains in the MOR ecosystem while maintaining strict control over its supply and minting rights.

## Key Features

1. Omnichain compatibility: built on LayerZero’s OFT (OApp v2) for seamless token transfers across chains.
2. ERC20 compliant: supports standard ERC20 interface (IERC20), including allowance-based `burnFrom`.
3. Minting control: only approved minters (set by contract owner, `L2MessageReceiver` as default) can mint new MOR tokens.
4. Burnable: users can burn their own tokens or those they’ve been approved to spend.
5. Interface support: implements `IMOROFT`, `IERC20`, `IOAppCore`, and `IERC165` for interoperability.

## Notes

Standard [ERC20](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20) and [OFT](https://docs.layerzero.network/v2/developers/evm/oft/quickstart) functions are not listed below.

## Storage

### isMinter

Returns `true` when the address has rights to mint tokens. `isMinter[<address>]`

```solidity
mapping(address => bool) public isMinter;
```

## Functions with restricted access

### updateMinter

Add or remove rights for `minter_` to call the `mint` function.

```solidity
function updateMinter(address minter_, bool status_) external onlyOwner;
```

| Name      | Description                                                                             |
| --------- | --------------------------------------------------------------------------------------- |
| `minter_` | The new or existed minter address.                                                      |
| `status_` | The true, when we want to add new minter, and false when we want tot remove the rights. |

### mint

Mints new tokens to the specified account. This function can only be called by the `_minter_` – `L2MessageReceiver`.

```solidity
function mint(address account_, uint256 amount_) public
```

| Name       | Description                             |
| ---------- | --------------------------------------- |
| `account_` | The account to which tokens are minted. |
| `amount_`  | The number of tokens to mint.           |

## Functions

### burn

Burns a specified amount of tokens from the caller's account, reducing the total supply.

```solidity
function burn(uint256 amount_) public
```

| Name      | Description                                                                             |
| --------- | --------------------------------------------------------------------------------------- |
| `amount_` | The number of tokens to be burned (removed) from the total supply and caller's account. |

### burnFrom

Burns a specified amount of tokens from the specified account, reducing the total supply. The caller must have allowance for at least the specified amount of tokens.

```solidity
function burnFrom(address account_, uint256 amount_) public
```

| Name       | Description                                                        |
| ---------- | ------------------------------------------------------------------ |
| `account_` | The account from which to burn tokens.                             |
| `amount_`  | The number of tokens to be burned (removed) from the total supply. |

## Read functions

### supportsInterface

Used for interface detection (ERC165). Returns `true` if the contract supports a specific `interfaceId_`. Supports `IMOROFT`, `IERC165`.

```solidity
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
```


# Deployed contracts

## Mainnet

### Arbitrum One

<table><thead><tr><th width="203.89453125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>MOROFT</code></td><td><a href="https://arbiscan.io/address/0x092baadb7def4c3981454dd9c0a0d7ff07bcfc86"><kbd>0x092baadb7def4c3981454dd9c0a0d7ff07bcfc86</kbd></a></td></tr></tbody></table>

### Base Mainnet

<table><thead><tr><th width="203.17578125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>MOROFT</code></td><td><a href="https://basescan.org/address/0x7431ada8a591c955a994a21710752ef9b882b8e3"><kbd>0x7431ada8a591c955a994a21710752ef9b882b8e3</kbd></a></td></tr></tbody></table>

## Testnet

### Arbitrum Sepolia

<table><thead><tr><th width="203.89453125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>MOROFT</code></td><td><a href="https://sepolia.arbiscan.io/address/0x34a285a1b1c166420df5b6630132542923b5b27e"><kbd>0x34a285a1b1c166420df5b6630132542923b5b27e</kbd></a></td></tr></tbody></table>

### Base Sepolia

<table><thead><tr><th width="203.17578125">Name</th><th>Address</th></tr></thead><tbody><tr><td><code>MOROFT</code></td><td><a href="https://sepolia.basescan.org/address/0x5C80Ddd187054E1E4aBBfFCD750498e81d34FfA3"><kbd>0x5C80Ddd187054E1E4aBBfFCD750498e81d34FfA3</kbd></a></td></tr></tbody></table>


# MOR 20 Contracts

{% hint style="warning" %}
**This documentation is for an early implementation of the MOR20 smart contracts, subject to change. Before conducting a Fair Launch, consider coordinating with other contributors in the** [**MOR20 chat**](https://discord.com/channels/1151741790408429580/1228219372317966409) **in the Morpheus Discord.**
{% endhint %}

MOR20 is a standardized implementation of the Morpheus [Techno Capital Machine](/tokenomics/techno-capital-machine) that can be used to fairly launch new projects while ensuring alignment with the Morpheus ethos and its community.

As in the case of Morpheus itself, a MOR20 token launch consists of an omnichain ERC20 token (Arbitrum, Ethereum, Base), utilizing LayerZero's OFT token standard, as well as an Ethereum staking contract for Capital Providers (stETH) on Layer 1 (Ethereum). Additional helper contracts are used for cross-chain communication and rewards calculation. Projects that launch using MOR20 can use other chain combinations.

This design enables a fair token distribution among Capital providers (and other ecosystem participants), with yield from staked Ethereum used to create [Protocol-Owned Liquidity](/tokenomics/protocol-owned-liquidity-pol).

### Contracts Architecture

A MOR20 deployment consists of the following contracts:

* `ERC20MOR` – the project's reward token
* `Distribution` – used to lock capital for the Techno Capital Machine and claim rewards
* `LinearDistributionIntervalDecrease` – a library for calculating rewards
* `L1Sender` – sends MOR minting requests; wraps and transfers stETH to L2
* `L2MessageReceiver` – receives and processes MOR minting requests on L2
* `L2TokenReceiverV2` – receives wstETH and manages Protocol-Owned Liquidity on L2

These contracts are functionally equivalent to those used by the Morpheus token itself.&#x20;

### Contracts Deployment

MOR20 contracts are deployed using the `Mor20FactoryL1` and `Mor20FactoryL2` factory contracts:

* `deployMor20OnL1` on `Mor20FactoryL1` deploys the `Distribution` and `L1Sender` contracts.
* `deployMor20OnL2` on `Mor20FactoryL2` deploys the `ERC20MOR` (the project's reward token), `L2MessageReceiver`, and `L2TokenReceiver` contracts.

These methods can be called in any order; however, before calling either method, the deployer should know the counterfactual deployment addresses of the second method, which can be calculated using `predictMor20Address`.

You can find the full guidance on [Github](https://github.com/MorpheusAIs/MOR20) or ask your questions in [Discord.](https://discord.com/channels/1151741790408429580/1228219372317966409)


# Multisignature account

As Morpheus develops in a fully decentralized and open-source manner, there is a need to deploy, manage, and upgrade Smart Contracts until all functions are fully automated in the future. A multisignature account is essential for ensuring transparency and security, especially since Morpheus contracts hold tens massive amount of ETH.

### Set Up Process and Key Holders

Based on recommendations from cybersecurity experts and auditors, a  [Gnosis SAFE](https://app.safe.global/) multisignature Smart Contract has been deployed on the [Ethereum](https://etherscan.io/address/0x1FE04BC15Cf2c5A2d41a0b3a96725596676eBa1E), [Base](https://basescan.org/address/0xf3ef00168dd40eae68a7e670d56c7b8724e0c183) and [Arbitrum](https://arbiscan.io/address/0x151c2b49CdEC10B150B2763dF3d1C00D70C90956) chains. This setup requires 5 out of 9 key holders to sign transactions:

* All key holders are trusted community members.
* Each key holder has extensive experience in cybersecurity and between 6 to 12 years in the crypto space.
* The key holders are geographically and jurisdictionally diverse.
* None of the key holders belong to the same company.
* For personal security reasons, the identities of the key holders will remain confidential.

### Multisignature Evolution

It’s important to note that the key holders have minimal control over the Smart Contracts. Most of the contract functions cannot be modified by the admin (which is controlled by the multisig). As the Smart Contracts evolve and mature, it is expected that the admin key may eventually become unnecessary and burned. However, this decision must be carefully considered, as it would make future upgrades by the community more difficult.


# Security Audits

Morpheus’ decentralize architecture is built on Smart Contracts. To ensure safety, reliability, trust, and scalability on a global scale, maintaining the highest level of cybersecurity is essential.

Morpheus prioritizes security by subjecting its Smart Contracts to rigorous audits, performed by both experts and independent white-hat hackers through [Bug Bounty Program](/security-audits/morpheus-bug-bounty-program). Even the smallest upgrades to the Smart Contracts undergo a thorough audit process.

You can find the latest audit below, and the full list is publicly available on [GitHub](https://github.com/MorpheusAIs/Docs/tree/main/Security%20Audit%20Reports).

{% file src="/files/9VPqI30yQvt8fOSKL8Nv" %}
MOR OFT Audit Report
{% endfile %}

{% file src="/files/j8W7SpCuYKcjLhpPeEAc" %}
MOR20 Contracts Audit Report
{% endfile %}

{% file src="/files/SAEhjGQwvfJRUgXEQban" %}
1st Morpheus Lumerin Compute Contract Audit Report
{% endfile %}

{% file src="/files/Uqw9gM7aD116myfOYNla" %}
2nd Morpheus Lumerin Compute Contract Audit Report
{% endfile %}

{% file src="/files/22nxGAUakWHHQG8Zs2RX" %}
Distribution V3 (Capital Rewards Staking) Audit Report
{% endfile %}

{% file src="/files/Mk8XIZXhJpZ20nkWdSG6" %}
Distribution V3 (Code Rewards Staking) Audit Report
{% endfile %}

{% file src="/files/ETSwLRGftrqW6JScgB76" %}
Distribution V4 (Claim Lock) Audit Report
{% endfile %}

{% file src="/files/kcuSsixEIX1wTZcGS9hI" %}
Distribution V5 (Referral Program) Audit Report
{% endfile %}

{% file src="/files/sVenCfCIK0l7il1pDjyR" %}
Morpheus Capital V2 Zenith Audit Report
{% endfile %}

{% file src="/files/KOJyfGqdOAqIHDWNuEkZ" %}
Morpheus Capital V2 Code4rena Audit Report
{% endfile %}


# Morpheus Bug Bounty Program

Public bug bounty programs are a critical part of Morpheus’ robust cybersecurity strategy. By engaging a global community of security researchers and ethical hackers with diverse expertise, potential vulnerabilities can be identified and resolved before they are exploited.

Morpheus offers rewards ranging from **$500 to $150,000** for eligible discoveries, depending on the severity of the vulnerability. The rewards are paid from a [Protection Fund.](/security-audits/protection-fund)

### Scope:

* **Primary Scope**: Vulnerabilities in the on-chain Morpheus Protocol contracts listed in [Smart Contracts](/smart-contracts).
* **Secondary Scope**: Vulnerabilities in the Morpheus [**User Interface**](https://dashboard.mor.org/#/capital?network=mainnet) that could lead to the exploitation of user accounts.
* **Out of Scope**: Test contracts (Sepolia or other testnets) and contracts built by third-party developers unless they affect the Morpheus Protocol or Interface.

To learn more about the full terms, eligibility criteria, and disclosure process, follow this [link](https://github.com/MorpheusAIs/Docs/blob/main/Security%20Audit%20Reports/Bug%20Bounty%20Program.md).


# Protection Fund

Bugs and errors in software are inevitable, as seen in the history of blockchain from Bitcoin’s two unintentional hard forks to The DAO incident during Ethereum’s early days. Planning ahead for such scenarios is a wise approach to mitigating risks and protecting against potential vulnerabilities.

The Morpheus [Tokenomics](/tokenomics) allocates 4% of all MOR emissions to the **Protection Fund**, which can be used in the following cases:

* Discovery and responsible disclosure of vulnerabilities in [Morpheus Smart Contracts](/smart-contracts) through the [Bug Bounty Program](/security-audits/morpheus-bug-bounty-program).
* Payments for [cybersecurity audits](/security-audits) of Morpheus Smart Contracts.
* Compensation for user losses caused by attacks or bugs in Morpheus software.
* Other initiatives aimed at strengthening the ecosystem’s security.

The Protection Fund is managed by the community-controlled [Multisignature Accoun](/smart-contracts/multisig)t, with claims made quarterly. A draft process for payments approval and release is available on [GitHub](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Protection%20Fund%20Details.md) and is still under discussion.

Additionally, there is a community-proposed concept for [Protection Fund Diversification](https://github.com/MorpheusAIs/MRC/blob/main/PENDING/MRC23.md)**.** \
\
You're welcome to join the discussion on [Discord.](https://discord.com/channels/1151741790408429580/1215401416659832842)


# FAQs\`

Welcome to the Morpheus FAQ section!&#x20;

Here, you'll find answers to common questions about the Morpheus, its technology, MOR token, contributors, MOReconomics and rewards.  This section is designed to provide clear, concise explanations to help you better understand how Morpheus works and how you can get involved.

### GENERAL QUESTIONS

<details>

<summary><strong>What is Morpheus?</strong></summary>

Morpheus is the decentralized infrastructure layer where anyone can **build**, **deploy**, and **scale** AI without gatekeepers.

It combines yield-powered tokenomics, decentralized compute, and open-source code into a permissionless network — with the native token [**MOR**](https://gitbook.mor.org/tokenomics/mor-emissions) aligning incentives through daily emissions to four contributor groups: Capital, Compute, Code, and Builders.

</details>

<details>

<summary><strong>Who are the founders?</strong></summary>

There are no founders. The anonymous authors who called themselves Morpheus, Trinity, and Neo published [the paper](https://drive.google.com/file/d/1GA_CWGFkKYSX-qOJO5Hl-LVb0CUs6e0M/view?usp=sharing) on September 2nd, 2023, marking the beginning of Morpheus.

</details>

<details>

<summary><strong>Who is on the team?</strong></summary>

There is no formal team, company or foundation. Morpheus is decentralized and driven by the community of open source contributors.

</details>

<details>

<summary><strong>Is Morpheus Proof of Stake or Proof of Work chain?</strong></summary>

Neither of these. Morpheus is not a blockchain, but rather a chain agnostic set of smart contracts and decentralized software.

</details>

<details>

<summary><strong>Are there any plans for Morpheus to have its own chain in the future?</strong></summary>

At the moment, there are no such plans, but it's not ruled out in the future.

</details>

<details>

<summary><strong>How can I earn MOR?</strong></summary>

By becoming a [contributor](/meet-morpheus/morpheus-contributors) in one of four categories:

* Capital provider.
* Code provider.
* App builder.
* Compute provider.

</details>

<details>

<summary><strong>What is the purpose of each category of contributors?</strong></summary>

* **Code providers** contribute to Morpheus code base for ongoing development, upgrades and improvements.
* **Compute providers** provide the main resource for AI, which is computation.
* **Application Builders** ensure utilization of network resources and produce innovative AI solutions for users.
* **Capital providers** generate liquidity streams for the ecosystem.

</details>

<details>

<summary><strong>Who can I contact regarding cooperation/marketing proposals?</strong></summary>

As the open source project, Morpheus doesn’t have a team or a person responsible for collaborations. You don't need anyone's permission to talk about Morpheus or add value as a Contributor.

</details>

<details>

<summary><strong>What is MOR20?</strong></summary>

MOR20 is a smart contract standard projects can utilize for fair launches.\
Please visit the [MOR20 page](/tokenomics/techno-capital-machine/mor-20-fair-launch-standard) for more information.

</details>

<details>

<summary><strong>Is there a bug bounty program?</strong></summary>

There is. Ethical hackers and cybersecurity experts can get up to $150,000 as reward for eligible discoveries in proportion to the severity of the vulnerability.\
Learn more about at [Morpheus Bug Bounty Program](/security-audits/morpheus-bug-bounty-program)

</details>

<details>

<summary><strong>Are Morpheus contracts audited?</strong></summary>

Yes, additionally to three tier initial audit process, any improvements or adjustments to the contracts undergo a cybersecurity audit.\
The list of audits is available in [Security Audits](/security-audits)

</details>

<details>

<summary><strong>Where can I find a list of key Morpheus links?</strong></summary>

Please visit [Verified Links](/verified-links) page.

</details>

<details>

<summary><strong>Where can I get support and ask questions?</strong></summary>

Community members would love to assist you in Discord [#tech-support](https://discord.com/channels/1151741790408429580/1183666837460897832) channel.

</details>

{% hint style="danger" %}
**Beware of scams, anyone who message you with proposal to help is likely a scammer**
{% endhint %}


# MOR Token and Liquidity

<details>

<summary><strong>What is the utility of MOR?</strong></summary>

MOR is the utility token that powers the Morpheus network, enabling access to compute resources and rewarding ecosystem contributors. Holders can stake MOR to support applications and smart agents, directing emissions to them and getting benefits in return. MOR also serves as the primary asset for AI applications within the Morpheus ecosystem, akin to ETH for Ethereum, and is used for staking MOR across various functions — compute, development, and rewards — ensuring the token's central role in network operations.

</details>

<details>

<summary><strong>What chains is the MOR token located on?</strong></summary>

Currently, the MOR token is deployed on Arbitrum, Ethereum, and Base chains.

</details>

<details>

<summary><strong>What are the addresses of the MOR token smart contract?</strong></summary>

**Arbitrum:** [0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86](https://arbiscan.io/token/0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86)

**Ethereum:** [0xcBB8f1BDA10b9696c57E13BC128Fe674769DCEc0](https://etherscan.io/address/0xcBB8f1BDA10b9696c57E13BC128Fe674769DCEc0)

**Base:** [0x7431ada8a591c955a994a21710752ef9b882b8e3](https://basescan.org/address/0x7431ada8a591c955a994a21710752ef9b882b8e3)

</details>

<details>

<summary><strong>Where can I buy the token?</strong></summary>

Please find the list of markets on [CoinGecko](https://www.coingecko.com/en/coins/morpheusai)

</details>

<details>

<summary><strong>Can I buy MOR if I don’t have wETH, but ETH and USDC?</strong></summary>

Yes, you can buy the token using any liquid token available on the Uniswap DEX. In this case, your token will be exchanged for wETH and then for MOR.

</details>

<details>

<summary><strong>How can I check that these links are legitimate?</strong></summary>

All the relevant and verified links are available in the [Morpheus Discord server](https://discord.com/channels/1151741790408429580/1183934719155515463) and in [Verified Links](/verified-links)

</details>

<details>

<summary><strong>Was there a presale, and what is the vesting schedule?</strong></summary>

There was NO presale, pre-mine, or any type of token allocations as it’s a [fair launch.](/meet-morpheus/what-is-morpheus)

</details>

<details>

<summary><strong>What is a fair launch?</strong></summary>

It's a method of launching the MOR token with equal conditions for all participants, without pre-mine and allocations for the team, founders, investors, etc. MOR can only be earned or purchased.

</details>

<details>

<summary><strong>What is the MOR maximum supply?</strong></summary>

42,000,000 tokens that will be released over 16 years.

</details>

<details>

<summary><strong>Can I know more about tokenomics?</strong></summary>

Yes, please visit[Tokenomics](/tokenomics) page.

</details>

<details>

<summary><strong>What is Protocol Owned Liquidity (PoL)?</strong></summary>

It's liquidity that is owned and controlled by the protocol itself, rather than by individual liquidity providers. This helps ensure the protocol's long-term sustainability and independence.\
It's fully explained in [Protocol-Owned Liquidity (PoL)](/tokenomics/protocol-owned-liquidity-pol)

</details>

<details>

<summary><strong>How is the PoL created?</strong></summary>

Morpheus utilizes part of the yield generated by Capital Providers to buy back MOR from the open market, combine it with the remaining wETH, and add it to the Protocol owned Liquidity.

</details>

<details>

<summary><strong>Where can I get data about MOR relevant data on Morpheus emissions and supply?</strong></summary>

You can get these data from [Morpheus CoinGecko page](https://www.coingecko.com/en/coins/morpheusai), [Morpheus CoinMarketCap page](https://coinmarketcap.com/currencies/morpheus/) or community websites:

* <https://morlord.com/>
* Discord [info-bot](https://discord.com/channels/1151741790408429580/1228051092323963020), use `/info` for a list of all commands.

</details>

<details>

<summary><strong>When will Morpheus be listed on tier-1 centralized exchanges, like Binance?</strong></summary>

It’s best to ask the exchange representatives directly as they make the listing decisions.

</details>

<details>

<summary><strong>Where can I get support and ask questions?</strong></summary>

Community members would love to assist you in the [**#tech-support**](https://discord.com/channels/1151741790408429580/1183666837460897832) Discord channel.

</details>

{% hint style="danger" %}
**Beware of scams, anyone who message you with proposal to help is likely a scammer**
{% endhint %}


# Power Factor Multiplier

{% hint style="info" %}
Capital Providers have a default **90-day vesting period** for MOR rewards. \
Each time a user deposits stETH, they are able to claim their MOR rewards after 90 days, unless they choose to stake for a longer period. Subsequent claims are also be available every 90 days following each claim or deposit.
{% endhint %}

<details>

<summary><strong>Why does Morpheus need Power Factor?</strong></summary>

[Power Factor](/tokenomics/power-factor-multiplier) has been introduced as a community initiative to close the negative feedback loop at the capital providers bucket and separate the real contributors from short-term opportunists.

</details>

<details>

<summary><strong>How does the multiplier work?</strong></summary>

In simple terms, Morpheus contributors can lock MOR reward claims for a future date. In exchange, contributors get a "Power Factor Multiplier" that amplifies their MOR rewards.

</details>

<details>

<summary><strong>How is the Power Factor determined?</strong></summary>

The Power Factor mirrors the dilution rate due to daily emissions contributors experience while staking the MOR rewards. The equation can be found in the [MRC42](https://github.com/MorpheusAIs/MRC/blob/main/IN%20PROGRESS/MRC42.md).

</details>

<details>

<summary><strong>What is the maximum Power Factor multiplier?</strong></summary>

The maximum Power Factor multiplier is 10.7x

</details>

<details>

<summary><strong>For how long can I stake my rewards?</strong></summary>

There are no limits, but the Power Factor starts to grow from 1x after approximately seven months of staking and reaches its maximum of 10.7x if rewards are staked for seven years.

</details>

<details>

<summary><strong>Can I stake MOR that I already have in my wallet?</strong></summary>

No, only future MOR reward claims can participate in this staking.

</details>

<details>

<summary><strong>Who is eligible for rewards staking?</strong></summary>

All four types of Morpheus contributions (Code, Capital, Compute, or Builders) can apply multiplier to their reward claims.

</details>

<details>

<summary><strong>I'm a contributor, do I have to lock my rewards?</strong></summary>

Lock of rewards is not mandatory, but without it, you will not gain Power Factor.

</details>

<details>

<summary><strong>Can I decrease or increase lock period?</strong></summary>

The lock period can only be increased.

</details>

<details>

<summary><strong>Can I claim rewards earlier?</strong></summary>

The user is not able to claim their MOR rewards until the end of the lock period.

</details>

<details>

<summary><strong>MRC states that every transaction will recalculate Power. I’d like to know more.</strong></summary>

Not every transaction will trigger recalculation, but only transactions with the Capital contract, due to the technical specifics of the contract. For example, depositing or withdrawing stETH for capital providers, or increasing or decreasing weights for code contributors.

</details>

<details>

<summary><strong>If I want to buy or sell MOR from the wallet where rewards are locked, will this trigger recalculation?</strong></summary>

No, because these transactions do not call functions of the Capital contract.

</details>

<details>

<summary><strong>Do lock of rewards affect MOR emissions?</strong></summary>

No, it has no impact on daily MOR emissions, but due to locks, fewer MOR tokens will flow into circulation.

</details>

<details>

<summary><strong>What should I do to get Power Factor?</strong></summary>

You will be able to do that via the [dashboard](https://dashboard.mor.org/#/capital?network=mainnet) or directly [through the smart contract](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/FAQs%20%26%20Guides/Guides/MOR/Mainnet/MOR%20Capital%20Rewards%20Staking%20Mainnet%20Contract%20Guide.md).&#x20;

</details>

<details>

<summary><strong>I'm a capital contributor. If I lock my reward, will I be able to withdraw my deposit assest?</strong></summary>

Nothing changes the ability of capital contributors to withdraw their assets (beyond the normal 7 days), only the claiming of MOR rewards is delayed. However, when you withdraw deposited assets, you will no longer get rewards.

</details>

<details>

<summary><strong>I have a question I didn’t find the answer to.</strong></summary>

Please ask it in the Discord in the [#capital-providers](https://discord.com/channels/1151741790408429580/1167520881908666569) or [#code-providers](https://discord.com/channels/1151741790408429580/1167520984849469530) channels.

</details>

{% hint style="danger" %}
**Beware of scams, anyone who message you with proposal to help is likely a scammer**
{% endhint %}


# Capital Providers

<details>

<summary><strong>How can I become a capital provider?</strong></summary>

You need to deposit supported yield bearing assets into the Morpheus Smart contract on Ethereum mainnet.

</details>

<details>

<summary><strong>How can I make a deposit?</strong></summary>

Please visit <https://dashboard.mor.org/>

</details>

<details>

<summary>W<strong>hich chain should I supply capital?</strong></summary>

Currently it's Ethereum mainnet. The list of chains will be expanded over time.

</details>

<details>

<summary><strong>What is the address of the smart contract for deposits?</strong></summary>

You can find the link on [Smart Contracts](/smart-contracts) page.

</details>

<details>

<summary><strong>How does Morpheus benefit from my deposit?</strong></summary>

The protocol leverages yield generated by assets to establish[ Protocol-Owned Liquidity.](/tokenomics/protocol-owned-liquidity-pol) The yield is allocated to MOR buybacks from the open market, which are then combined with burns and locks to support future Epochs.

</details>

<details>

<summary><strong>Do I bear the risk of impermanent loss?</strong></summary>

No, there is no impermanent loss risk. You withdraw the same amount you deposited.

</details>

<details>

<summary><strong>Do I have to pay transaction fees?</strong></summary>

Yes, you do. Since the claim transaction is generated on the Ethereum blockchain, and the MOR rewards will be received on the Arbitrum chain.

</details>

<details>

<summary><strong>How quickly will I receive my tokens?</strong></summary>

After confirming the claim transaction, you will receive your tokens within a few minutes.

</details>

<details>

<summary><strong>Is deposited assets locked?</strong></summary>

They are not locked. You are free to withdraw at any time after the 7-day initial lock-up period.

</details>

<details>

<summary><strong>Why is there a 7-day lock-up period for deposit?</strong></summary>

This measure was introduced to avoid people gaming the yield timing, as the protocol rewards in advance from the moment you deposit, with yield generated once a day.

</details>

<details>

<summary><strong>How do rewards distribute?</strong></summary>

24% of MOR emissions are designated for capital providers and divided proportionally to a user's share in the total generated yield multiplied by [Power Factor](/faqs/power-factor-multiplier).

</details>

<details>

<summary><strong>Do I lose earned MOR rewards if I decide to withdraw a deposit?</strong></summary>

No, you don’t, but you will not earn rewards any longer as you are not providing the capital anymore.

</details>

<details>

<summary><strong>Has the contract I deposit capital into been audited?</strong></summary>

Yes, both the community and a dedicated auditor have reviewed the Smart Contracts. See the reports on [Security Audits](/security-audits) page.

</details>

<details>

<summary><strong>How is the Capital contract managed?</strong></summary>

There are 5 of 9 [multisignatute account ](/smart-contracts/multisig)managed by community-trusted open-source contributors. The multisignature address is [MOR.ETH](https://etherscan.io/address/0x1FE04BC15Cf2c5A2d41a0b3a96725596676eBa1E).

</details>

<details>

<summary><strong>What are the risks of providing capital?</strong></summary>

There are always risks with smart contracts like bugs or vulnerabilities. To ensure a high level of security, the contracts have undergone multiple levels of audits, including community audits, cybersecurity company audits, and a public bug bounty campaign. Security reports are available on [Security Audits](/security-audits) page. That's also why the [Protection Fund](/security-audits/protection-fund), 4% of emissions, exists.

</details>

<details>

<summary><strong>Who should I contact if I encounter difficulties?</strong></summary>

The community is always ready to provide support. Please describe your issue in the Discord [support channel](https://discord.com/channels/1151741790408429580/1183666837460897832).

</details>

{% hint style="danger" %}
**Beware of scams, anyone who message you with proposal to help is likely a scammer**
{% endhint %}


# Code Providers

<details>

<summary><strong>What do code providers do?</strong></summary>

Code providers contribute to Morpheus code base for ongoing development, upgrades, and improvements.

</details>

<details>

<summary><strong>How can I get involved with Morpheus as a code provider?</strong></summary>

An onboarding process is described in the [Coder Guide](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Code%20Providers/Coder%20Guide.md).

</details>

<details>

<summary><strong>What are the requirements for code contributors?</strong></summary>

There are [Code Contributor Best Practices](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Code%20Providers/Code%20Contributor%20Best%20Practices.md) on GitHub.

</details>

<details>

<summary><strong>How do code providers get rewarded?</strong></summary>

They get MOR emissions depending on their contributed weights vs the total amount of weights contributed.

</details>

<details>

<summary><strong>What are the weights?</strong></summary>

Weight is the unit that represents contribution value. The weights concept is explained [here](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Code%20Providers/Code%20Contributor%20Weights%20Guide.md).

</details>

<details>

<summary><strong>Can I be paid in USD or stablecoins?</strong></summary>

No, code providers are rewarded only in MOR.

</details>

<details>

<summary><strong>How do I get in touch with other builders for collaborations?</strong></summary>

The Discord server Accelerator Corner is your go-to place ⁠=> [Join here](https://discord.gg/morpheusai).

</details>

<details>

<summary><strong>Where can I see a task list?</strong></summary>

There is no task list available. Developers build what they want based on their experience and belief in its value for Morpheus. GitHub maintainers act as judges to merge contributors' work. Coders here compete, but there are no guarantees that anyone will use the code until it's released.

</details>

<details>

<summary><strong>Are there other ways to get involved?</strong></summary>

You can contribute by submitting a proposal as a Morpheus Request for Comments (MRC). Explore the guidance [here](https://github.com/MorpheusAIs/MRC/blob/main/MRC00.md).

</details>

<details>

<summary><strong>Where can I get support and ask questions?</strong></summary>

Community members would love to assist you in the [**#code-provider**](https://discord.com/channels/1151741790408429580/1167520984849469530) Discord channel.

</details>

{% hint style="danger" %}
**Beware of scams, anyone who message you with proposal to help is likely a scammer**
{% endhint %}


# Compute Providers

### Testnet

<details>

<summary><strong>What do compute providers do?</strong></summary>

The main role of compute providers is to provide computation, a vital AI resource for inference, in a decentralized way.

</details>

<details>

<summary><strong>Is the Compute testnet launched?</strong></summary>

Yes, it started in June 2024 on Arbitrum Sepolia.

</details>

<details>

<summary><strong>What is the purpose of the Compute testnet?</strong></summary>

The Compute testnet aims to test the network’s infrastructure under various conditions, validate the performance and reliability of compute providers, ensure all compensation and incentive systems are working correctly, and ensure the proper functioning of the Compute Contract and proxy Router.

</details>

<details>

<summary><strong>At what stage is the Compute testnet right now? What is the status?</strong></summary>

The developers and community are actively working to bring the documentation up to speed so everyone with appropriate hardware can participate. The backend server and front-end UI are functional, and the pieces are in place. The testnet grows as more providers sign on by providing their private compute AI engines. There are already some hosted models running now that consumers running the UI or API can connect to by staking and using Sepolia Testnet tokens (saMOR and seETH which you can get via [Morfaucet](https://morfaucet.xyz/) and the Arbitrum Sepolia faucet links) to purchase bids and run inference.

</details>

<details>

<summary><strong>How long will the Compute testnet last?</strong></summary>

As long as necessary to get a robust testnet ecosystem in place where primary aspects of the provider and consumer software are running as expected. Some version of the testnet will likely live on in the future after the mainnet to test new features.

</details>

<details>

<summary><strong>Are there any restrictions (like whitelists) to join the testnet?</strong></summary>

As of right now, anyone can connect to the smart contract running on Arbitrum Sepolia testnet, which is currently 0x8e19288d908b2d9f8d7c539c74c899808ac3de45. More information can be found in the [Morpheus-Lumerin-Node repository](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node).

</details>

<details>

<summary><strong>I have no technical knowledge, how can I participate? What steps do I need to take to become a Compute provider?</strong></summary>

At this stage, you may be better off waiting until the developers and early adopter technicians have worked through the early technical challenges to provide you a better user experience in the future that requires minimal technical know-how.

</details>

<details>

<summary><strong>Can I be a compute provider in the testnet from my laptop?</strong></summary>

In the beginning, most likely not. Being a compute provider implies that you have a significant investment in hardware, GPU, and development for your own models that you want to distribute on Morpheus. If you have that, then you probably have the technical know-how to run the proxy-router.

</details>

<details>

<summary><strong>Can users of Smart Agents participate in the Compute testnet or is it only for Compute providers?</strong></summary>

In the future, the various smart agents and chat UI will interact with decentralized compute, and there will likely be options to connect to mainnet or testnet compute.

</details>

<details>

<summary><strong>Will there be any rewards for participating in the Compute testnet?</strong></summary>

No, participants of the Compute testnet are not entitled to any rewards or compensation.

</details>

### Mainnet

<details>

<summary><strong>What will the process look like when the compute goes live? Will I need to just download and install the node and click one button to share compute power of my PC?</strong></summary>

In the beginning, compute will likely be provided by serious hardware providers with dedicated servers. Over time, as staking and reputation systems develop to ensure quality of service, anyone will ideally be able to download the software and both consume and provide models which are compatible with their compute resources. The client will be an all-in-one UI for providing and consuming models via decentralized nodes communicating peer-to-peer offering up and consuming bids for compute models.

</details>

<details>

<summary><strong>I want to consume Morpheus' decentralized compute in the future. What do I need for this?</strong></summary>

In the future, the Morpheus AI tools will have both local and remote options for interacting with your own locally hosted models or connecting to the decentralized network of nodes via peer-to-peer routing using reputation and staking, which involves offers and bids for compute of various models. The providers will be rewarded for their contributions by the network, and the consumers will lock their MOR to open a session with the providers, unlocking their MOR at the end of the session.

</details>

<details>

<summary><strong>How will compute providers be rewarded?</strong></summary>

The Morpheus network pays compute providers only for compute actually provided through a competitive bid process.

</details>

<details>

<summary><strong>How much can I earn as a compute provider?</strong></summary>

It depends on what types of models you offer and how many concurrent sessions your hardware can serve.

</details>

<details>

<summary><strong>Is Morpheus Compute Node the same node other blockchains have?</strong></summary>

No, the Morpheus node is not that type of node that runs blockchain and processes transactions.

</details>

<details>

<summary><strong>When will the Compute mainnet be launched?</strong></summary>

Compute mainnet is estimated to launch in Q3-Q4 2024 once the testnet audits are fully cleared and core node software is ready for a stable production deployment.

</details>

<details>

<summary><strong>What is the whitelist in mainnet for?</strong></summary>

The whitelist is a temporary mechanism to ensure good actors seed the provider pool. Once seeded, the whitelist will be removed, and the MOR stake mechanism will take over to ensure economic alignment.

</details>

<details>

<summary><strong>How can I get on the whitelist?</strong></summary>

Post an introduction message in the Compute provider [Discord channel](https://discord.com/channels/1151741790408429580/1167520834139738289), and you will be connected with devs working on compute.

</details>

<details>

<summary><strong>What MOR stake is required to get whitelisted?</strong></summary>

Whitelisting is not based on stake amount. Whitelisting is based on known good actors with verifiable stable compute. Once the whitelist is turned off, the MOR stake requirement will be set at an appropriate level chosen by members of the Morpheus community to ensure economic alignment by providers.

</details>

<details>

<summary><strong>Do I obtain higher credibility as a Compute provider by holding more MOR than needed to get whitelisted?</strong></summary>

Holding MOR is not required to be whitelisted. Although, staked MOR may be included in the reputation algorithm.

</details>

<details>

<summary><strong>Is the Compute provider stake locked, or can it be slashed?</strong></summary>

Compute provider stake is only locked. There are no current plans for a slashing mechanism anywhere in the Morpheus ecosystem.

</details>

<details>

<summary><strong>What is a reputation system?</strong></summary>

The reputation system is an on-chain algorithm used for sorting providers according to user needs.

</details>

<details>

<summary><strong>How does the reputation system work?</strong></summary>

The reputation system will take into account metrics such as response performance, connection speed/lag, number of completed sessions, number of canceled sessions, total earnings, and marketplace bid amounts. These metrics will be used to sort and recommend providers to users when a new session is created.

</details>

<details>

<summary><strong>What penalties are in place for bad actors?</strong></summary>

Bad actor penalties are currently constrained to degraded reputation scores.

</details>

<details>

<summary><strong>Will the launch of the Compute mainnet lead to a large influx of tokens into the market and a possible dump?</strong></summary>

No, that won't happen. Since the budget is 1% of the previous day's Compute contract balance.

</details>

<details>

<summary><strong>What is the Compute Contract?</strong></summary>

The Compute Contract is the smart contract that has a MOR address, receives all emitted MOR allocated to the Compute bucket, tracks amounts owed to eligible providers, and pays MOR to eligible providers when providers request payment.

</details>

<details>

<summary><strong>What is the Compute Proxy Router?</strong></summary>

Compute Route is the software application that has a MOR address and negotiates the two-sided market between Users and Providers. The Router registers and tracks provider addresses and bids, processes requests from users, and instructs the Compute Contract to credit eligible providers for payment in MOR.

</details>

<details>

<summary><strong>I have a powerful gaming computer, can I be a Compute provider?</strong></summary>

Yes, absolutely, but keep in mind if you are providing compute, it is important to have your system online and stable. Otherwise, you will hurt your reputation.

</details>

<details>

<summary><strong>What is the minimum and recommended hardware configuration to be a Compute provider?</strong></summary>

Hardware recommendations greatly depend on the models you are offering. Hardware benchmarking reports would be the best source of information for this.

</details>

<details>

<summary><strong>How can I choose which model to serve, and which is optimal for my hardware configuration?</strong></summary>

If you are unsure about your system performance with different models, it would be best to download and run them locally for a while to see what your local user experience is like. This experience will be fairly close to the same experience remote users will have.

</details>

<details>

<summary><strong>I plan to buy a GPU, please advise on the best suited for serving Smart Agents?</strong></summary>

Morpheus Smart Agents will be incredibly lightweight and not need specialized hardware, but once again this greatly

depends on the tasks that the agent is asked to accomplish.

</details>

<details>

<summary><strong>Can I provide computation with ASICs?</strong></summary>

No.

</details>

<details>

<summary><strong>What steps do I need to take to become a Compute provider?</strong></summary>

1. Run a Morpheus node on a compute and make sure your ports are configured for inbound traffic.
2. Download and configure the model you want to provide.
3. Register as a provider in the on-chain provider registry.
4. Claim rewards periodically from the session router contract.

</details>

<details>

<summary><strong>The whitepaper mentions Filecoin as storage. Is that information outdated?</strong></summary>

Filecoin storage has not been implemented or planned currently. If community members wish to expand the system and implement it, they are welcome to do so.

</details>

<details>

<summary><strong>Can I train LLM models with Morpheus Compute?</strong></summary>

Not for v1, but we are hoping to achieve this with key partnerships.

</details>

<details>

<summary><strong>Is it correct to assume that Compute providers will not only need to run model inference but also the agent code itself?</strong></summary>

Agent code can run from anywhere as long as it has access to the resources it needs to achieve its objectives.

</details>

<details>

<summary><strong>Where can I get more information?</strong></summary>

* [Yellowstone Compute Model](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Yellowstone%20Compute%20Model.md)
* [Lake Travis - Decentralized AI Inference System](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Compute%20Providers/Lake%20Travis%20Decentralized%20AI%20Inference%20System.md)
* [Morpheus Lumerin Model document](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Compute%20Providers/Morpheus%20Lumerin%20Model.md)
* [Compute Node Repository](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node)

</details>

<details>

<summary><strong>Where can I get support and ask questions?</strong></summary>

Community members would love to assist you in the [**#tech-support**](https://discord.com/channels/1151741790408429580/1183666837460897832) Discord channel.

</details>

{% hint style="danger" %}
**Beware of scams, anyone who message you with proposal to help is likely a scammer**
{% endhint %}




---

[Next Page](/llms-full.txt/1)

