Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions network-rfc/11_tokenomics_v2.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Tokenomics 2.1

## Overview

Tokenomics 2.1 addresses the centralization issues of Tokenomics 2.0, namely:

- That there is a single (de-facto centralized) pool for providing SQD for yield, which makes SQD a security
- The lack of dynamic pricing and many parameters that has to be hard-coded/adjusted in a centralized (or, at best, DAO-like) fashion. The subscription fee is not established by an open market and the marketplace.
- Removing the treasury-initiated buyback-and-burn mechanics which makes SQD a security
- Moving the reward token out of scope
- Introducing the fee switch to the Portals (to be activated in the future if necessary)
- Making it possible to register Portals on EVMs (in particular, Base) and Solana. For Solana users, it opens up the posibility to pay in USDC or SOL.


## The SQD Flows

**Workers**
Workers serve the data and receive rewards in SQD. The reward depend on the number of served queries, the amount of delegated tokens and the uptime of the worker. The worker has to lock 100k SQD to participate in the network. The maximal amount of rewards distributed per worker and the delegators is controlled by a single parameter called `TARGET_APR`. The reward is then split abetween the worker and the delegators for the worker.

**Delegators**
Delegators delegate SQD to workers to get a part of the worker reward. Both the amount of delegated tokens and the served queries affect the reward per query served.

**Data consumers**
Data consumers query the network p2p using a Portal. The maximal bandwidth that can be consumed by a Portal is determined by the amount of SQD locked in the Portal contract. Thus, the data consumer either buys SQD on the open market and locks the desired amount themselves, or makes an _SQD Provision Offer_ to SQD holders willing to provide SQD in return to the fee.

An SQD Provision Offer is an agreement to lock SQD for a specified amount of time for a fee, paid as continuosly during the whole lock period. The fee is locked by the consumer in advance and can be paid in any of the supported tokens. Special conditions apply for extending the provision offer and withdrwals.

**SQD providers**
SQD providers hold SQD and fullfill the matching _SQD Provision Offers_. Active providers can advertise their target fees in advance to make the market and set the expectations for the data consumers.

## Emission reduction

The `TARGET_APR` currently set to 25% yearly, will be gradually reduced and replaced by the fees collected from the portals.
Comment thread
kalabukdima marked this conversation as resolved.

## Portal Payments

The are two options to get data through the portals:
- Lock SQD tokens (the existing flows)
- Pay a subscription fee in one of the supported tokens, so that the SQD is locked by one or multiple SQD providers.

**The subscription flow**

The user specifies:
- the required bandwidth (which translates into the required SQD to be locked)
- the terms (fix-term or auto-extension)
- the price (the dApp will provide the current quotes of the SQD providers to give a reasonable offer)

The user:
- creates a Portal Registration Contract
- makes the fee deposits
- the willing SQD providers lock the SQD for the required term

The fee is deducted every epoch and automatically split:
- 50% to the SQD providers
- 45% to the worker reward pool
- 5% gets burnt
Comment thread
kalabukdima marked this conversation as resolved.

The fee parameters are adjustable.

![image](https://gist.github.com/user-attachments/assets/9d3977ee-aa80-4a6f-a248-83656abc10e1)


## The fee switch

Apart from the fees collected from the subscription fees, Tokenomics 2.1 introduces a fee switch directly to the portals.
The fee switch is initiall set to zero, but can be switched on at a later time.

When it is on, the fee is deduced from SQD locked in every Portal contract, and distributed between burn and the reward pool.
That way even the users self-staking SQD will pay a usage tax. For SQD providers the tax may be compensated directly by the fee.


## Deployments to Solana and other networks

The Poral Registration factories allow deployments on foreign networks, such as Base and Solana, assuming the two-way bridging is possible. In order to integrate a foreign chain one would need

- Update the Worker nodes to listen to the registration events
- Establish a canonical "bridged" token on the target chain with minimal liqidity pools
- Implement bridging of the fees to be teleported to the host chain regularly, to top up the reward pool on the host chain
90 changes: 90 additions & 0 deletions network-rfc/12_contracts_design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Portal System


### Portal Creation and SQD Collection

The Portal System begins when a Data Consumer creates a new portal through the PortalFactory by specifying key parameters including the target amount of SQD tokens needed, deposit deadline, payment token, "budget".
Comment thread
Gradonsky marked this conversation as resolved.
Outdated

The data consumer allocation (contribution by the deployer) will be determined by the target amount that the data consumer is seeking.
Comment thread
Gradonsky marked this conversation as resolved.
Outdated

We are collecting 120% of the amount that will be set by SQD.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it configurable?


The factory deploys a single PortalProxy contract, an upgradeable instance that combines both the core distribution logic and SQD vault functionality into one unified contract.
Once deployed, SQD token providers can stake their tokens directly into the PortalProxy by calling the stake function with the portal address and desired amount.

During this collection phase, the portal remains in a "Collecting" state where it accumulates SQD deposits from multiple providers until either the target amount is reached or the deposit deadline passes.
If the target is met before the deadline, the data consumer can trigger the activate function to transition the portal to its active distribution phase.

However, if the deadline expires without reaching the target, the portal is marked as failed, triggering a full refund of both the consumer's budget and all staked SQD tokens back to their respective owners.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the deadline is very long? Can providers unlock their funds with the normal exit mechanism? If so, do we even need this cancellation?


### Active Distribution and Fee Routing
Once activated, the portal enters its Active state where it begins distributing

Throughout this active period, the data consumer can call the distribute function to inject tokens into the contract, which will be distributed across SQD providers etc.
This amount is distributed based on the FeeRouterModule, a separate admin-controlled contract responsible for splitting the fees according to configurable basis point allocations (defaulting to 50% for SQD providers, 45% for the worker reward pool, and 5% for burning).
Comment thread
Gradonsky marked this conversation as resolved.
Outdated

The FeeRouterModule holds the actual BPS.
During both the staking and distribution phases, the system can trigger external Hooks at key moments (before and after staking, distribution, and exits), allowing for customized behavior such as additional protocol token rewards layered on top of base distributions etc.
Similar to UniswapV4 Hooks.

### Reward Claims, Exits, and Closure

While the portal is active, SQD providers can claim their proportional share of accumulated rewards at any time by calling the claimRewards function on the PortalProxy, which calculates their share based on their staked balance relative to the total tokens in the portal and transfers the corresponding tokens to them. The portal continues distributing as long as the data consumer injects tokens through the distribute function, with all distributions based on the FeeRouterModule configured splits.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the claimRewards function calculate their share? I think you won't be able to account for past clamis this way, so you have to top up claimable amount at the distribution time. The same is already done in our WorkerRegistration contract


When SQD providers stake their tokens into the portal, they lock them for a minimum duration period.
Comment thread
Gradonsky marked this conversation as resolved.
Outdated
After this minimum lock period expires, providers can request to exit the portal by calling requestExit with their desired withdrawal amount.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what happens to the registered portal when the token withdrawal is requested? Do I understand correctly that we keep those extra 20% liquid in the pool contract to be able to refund immediately if needed? But what happens when they run out? SQD can't be unstacked immediately from the gateway contract, and if you request unstaking in advance, the portal will stop being active.

I'm starting to think that we may need a new, much simpler, portal registration contract

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed with @dzhelezov that locking funds was intended to protect token price.

I think an ideal solution would be something like this:

  • The raw portal registry contract allows immediate withdrawals but only for a limited amount per epoch (let's say 100k). If you request to withdraw more, funds will be gradually unlocked (reducing CU) and waiting on the contract to be collected.
  • The portal pool builds around this limitation to distribute already unlocked funds among requesters, making slow exits even slower when multiple people want to withdraw simultaneously. No additional limits on the portal pool side are needed then — it allows you to withdraw as fast as the core contract allows it.

This solution may be much harder to implement than "no withdrawal limits on the registry contract", so I think we can start with that one and make registry contract upgradeable to implement this logic later

However, exits are subject to a time-delay mechanism designed to prevent sudden liquidity shocks:
the exit delay consists of a base period of 1 epoch plus a percentual delay calculated by the amount being withdrawn.
The system allows a maximum of 1% of the total portal liquidity to exit per epoch, meaning if a provider wants to exit 5% of the liquidity, they must wait 1 epoch (base) plus 5 additional epochs (one epoch per 1% of liquidity), totaling 6 epochs before their full withdrawal is processed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be 1% of the total pool or fixed amount in SQD? I think we agreed on a number 100k SQD per epoch on the meeting

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don’t remember us agreeing on a fixed number, I recall we discussed it in percentage terms, since we still don’t know what the final required amount of SQD to run a portal will be. Do we already have a clear figure defined for that?

For example, if a provider holds 10% of the portal's total SQD and wants to exit their entire position, they would need to wait 1 base epoch + 10 epochs (for the 10% withdrawal) = 11 epochs total. This mechanism ensures gradual exits and maintains portal stability while still allowing providers to eventually withdraw their staked tokens along with any accumulated rewards.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will they have to wait for the completion of all 11 epochs to withdraw the full amount, or can part of it be already withdrawn after 1-2 epochs?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We unlock 1% per epoch to avoid flash exits. If the provider waits all 11 epochs without partial withdrawals, it effectively becomes a flash exit at the end


**Importantly, once a provider requests an exit, they stop earning rewards on the requested exit amount during the entire waiting period**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the replacement process work? Are new SQD providers allowed to enter the pool as soon as some existing provider requests an exit?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good point. I'll add it to the doc!


Throughout this entire process, the system maintains upgradeability through the proxy pattern (allowing the factory admin to deploy improved implementations without affecting existing portals), adjustable fee distributions (admins can modify the FeeRouterModule configuration to change allocation percentages), and emergency controls (pausing functionality at both the factory and individual portal levels for security purposes).



### Exit Delay Formula

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please also describe interfaces of all the contracts? I think this document should be more detailed and serve as a blueprint for the exact implementation

```
Total Exit Delay = Base Delay + Percentual Delay
Base Delay = 1 epoch (mandatory for all exits)
Percentual Delay = (Withdrawal Amount / Total Portal Liquidity) × 100 epochs
```


---

## State Transitions

```
Collecting → Active → Closed
Failed
```

- **Collecting**: Portal accepting SQD deposits, waiting to reach target before deadline
- **Active**: Target met, distributing tokens when injected.
- **Failed**: Deadline passed without reaching target, full refunds enabled
- **Closed**: Portal closed?


### To Discuss

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also talked about support for transferring the stake. Something to add on the next iteration probably, but maybe worth adding to the design doc

- The consumer's budget over the specified duration using a time-based linear vesting mechanism calculated as budget divided by duration to determine the payment rate per second in beginning?

1. **120% Collection Split**:
- Portal collects 120% of the target amount from SQD providers
- Where does the split happen?

2. **Withdrawal Coordination**:
- **GatewayRegistry has its own lock period**:
```solidity
require(operators[msg.sender].stake.lockEnd <= block.number, "Stake is locked");
```
- **Portal has epoch-based exit delays**: Base 1 epoch + percentual delay (1% per epoch)
- **Problem**: Two separate delay mechanisms
- When a provider requests exit from Portal, Portal needs to unstake from GatewayRegistry
- But GatewayRegistry requires `lockEnd <= block.number` to unstake
- How can we synchronize these two timelines? Should we base it on the minimum lock period plus a percentage of the GatewayRegistry lock? (Minimum + as Base the GatewayRegistry lock + percentual lock?)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say we should just set staking duration equal to one epoch from this document, and during the minimal lockup period the pool (proxy) contract just won't allow you to withdraw from the underlying gateway contract.
The only drawback I see is that computationUnitsAmount could be higher if locked for the entire minimal lockup period, but let's say it's the price you pay for locking borrowed funds instead of owned SQD


**Should we actually take this into account now? Any focus on developing an upgraded (V2) version of the current contracts that’s more compatible with the Portal contract?
The Portal Contract wille be anyways upgradealbe so we can go with the current implementation for now and i can design the contract, so it fits also the V2 later.**