Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 110 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

CrossCurve MetaLayer

CrossCurve MetaLayer

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

CrossCurve DAO

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Earn with CrossCurve

Loading...

Loading...

Loading...

user documentation

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Developer documentation

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

What is CrossCurve MetaLayer

CrossCurve MetaLayer is an orchestration layer built on top of liquidity routes.

Instead of providing access to a single DEX, bridge, or aggregator, MetaLayer operates one level higher - it connects multiple liquidity sources and execution systems into a unified routing layer. This allows CrossCurve to construct multi-step, cross-protocol, and cross-chain execution paths that are not available through direct integrations with individual protocols.

MetaLayer aggregates:

  • DEXs

  • Aggregators

  • Token bridges

and orchestrates them into optimized execution flows. A single route may include several sequential steps - for example, a swap via one DEX, followed by a bridge, and finalized by another aggregator on the destination network.

As a result, MetaLayer enables execution efficiency that cannot be achieved by standalone protocols.

The CrossCurve MetaLayer ecosystem consists of multiple products that can operate independently, but together form a composable system capable of solving complex liquidity routing problems through a single integration.

Why CrossCurve MetaLayer?

For Integrators

Integrating liquidity across multiple chains traditionally requires:

  • Maintaining N direct integrations with DEXs, bridges, and aggregators

  • Constantly updating routing logic as new protocols and paths emerge

  • Manually handling cross-chain execution and failure scenarios

  • Missing optimal execution paths due to fragmented infrastructure

The most critical pain point is the operational and engineering cost of maintaining multiple integrations.

CrossCurve MetaLayer replaces this complexity with a single integration.

By integrating once with the MetaLayer API, an integrator gains:

  • Access to all supported liquidity routes and their combinations

  • Automatic discovery of optimal execution paths

  • Reduced engineering overhead and lower maintenance costs

  • Faster time-to-market for Integrators

  • Seamless scalability as new protocols and networks are added

One integration unlocks all current and future routes - something that is fundamentally impossible with direct, protocol-level integrations.

For Blockchains

For blockchains, access to global liquidity usually requires significant upfront investment:

  • Incentivizing liquidity providers

or

  • Bootstrapping bridges with protocol-owned liquidity

With CrossCurve MetaLayer, blockchains can connect their native assets to the broader crypto market without allocating capital to liquidity bootstrap.

This means:

  • No need to incentivize LPs

  • No need to deploy a DEX to enable cross-chain swaps

  • No need to lock liquidity into bridge pools

Through MetaLayer, a blockchain gains frictionless access to external liquidity flows, enabling inflow of TVL from the broader crypto ecosystem. This lowers entry barriers for users and developers, improves UX, and supports organic ecosystem growth.

CrossCurve Ecosystem Products

CrossCurve MetaLayer is implemented through a set of composable products. Each product can be used independently, but together they form a unified orchestration system.

MetaLayer API

The primary integration point for developers and integrators.

Provides programmatic access to all supported liquidity routes and their combinations through a single API.

CrossCurve Token Bridge

The CrossCurve Token Bridge (ex Eywa Token Bridge ) is an infrastructure solution designed for the fluid movement of assets across multiple blockchains.

By integrating aggregation through the CrossCurve Metalayer, projects unlock Any-to-Any exchange capabilities (any token for any token).

CrossCurve Oracle Network

The CrossCurve Oracle Network (ex Eywa Oracle Network) is a decentralized cross-chain messaging service. It provides a robust solution for clients who require seamless communication between different blockchains but want to avoid the high costs and lengthy development cycles associated with building a proprietary messaging infrastructure. By leveraging CrossCurve’s pre-built oracle network, projects can focus on their core logic while ensuring secure and rapid data transmission across chains.

Consensus Bridge

CrossCurve Consensus Bridge is a high-security messaging service that utilizes multi-protocol validation. A message is only delivered to the recipient once it has been independently confirmed by several different messaging protocols, effectively eliminating any single point of failure.

This product is purpose-built for projects with stringent security requirements looking to mitigate the risks of cross-chain infrastructure exploits. If the compromise of a single messaging protocol poses an unacceptable risk to your business model, the Consensus Bridge provides the necessary resilience and peace of mind.

CrossCurve App

A user-facing application that demonstrates MetaLayer capabilities through a unified UX, showcasing how complex routes can be abstracted into simple user interactions.

Summary

CrossCurve MetaLayer is not a single protocol or a simple aggregator. It is an orchestration layer that turns fragmented liquidity infrastructure into a unified execution system.

For integrators, it replaces many integrations with one. For blockchains, it opens access to global liquidity without capital-intensive bootstrapping. For the ecosystem, it enables liquidity to flow freely across chains and protocols.

CrossCurve Consensus bridge

The CrossCurve Consensus Bridge addresses one of the key problems of modern cross-chain solutions — the vulnerability of bridges and the so-called “black swan” risk. A prime example of such a risk is the Multichain incident, after which Curve DAO withdrew its trust from bridges based on centralized governance.

The core issue lies in the fact that most existing bridges are controlled by a limited group of participants — validators or members of multisig groups. This makes them vulnerable and unstable. Classic examples of such failures include hacks or loss of funds in protocols such as Multichain, PolyNetwork, Wormhole, Nomad and Ronin.

Unlike the traditional PoA (proof-of-authority) solutions, the CrossCurve Consensus Bridge uses a validation model based on agreement between independent data transmission protocols. This architecture involves Axelar, LayerZero, Router Protocol, Asterizm and Chainlink CCIP. A transaction is completed only if consensus is reached among multiple sources. If the data diverges, the transaction is automatically rejected, preventing potential compromise and ensuring the safety of user funds.

How it works:

  • The user's assets are locked in the consensus bridge smart contract on the source network.

  • Transaction data is transmitted through multiple protocols simultaneously, and the smart contract of the target network verifies their consistency.

  • If consensus is reached, the transaction is finalized; otherwise, the funds are returned to the user.

Advantages:

  • Security: The risk of compromise is minimized thanks to consensus among several protocols — the likelihood of all protocols being hacked at the same time is virtually zero.

  • Decentralization: Bridge security does not depend on individual teams; the bridge smart contracts are governed by CrossCurve DAO, and the protocol’s liquidity is fully controlled by users.

  • Versatility: The consensus bridge supports the transmission of both tokens and data, making it a universal tool for cross-chain applications.

Consensus Bridge is not just a bridge—it is the transport layer of the CrossCurve Metalayer, providing a reliable connection between blockchains. It enables developers and users to safely transfer assets, data, and liquidity, forming the foundation for a scalable and resilient cross-chain ecosystem of the future.

CrossCurve Token Bridge

The CrossCurve Token Bridge lets projects present their token on other networks by locking their assets in smart contracts and issuing the token’s derivative on other networks. Our bridge allows you to move issued derivatives between blockchains in all directions, without having to return to the original token lock network using Cross-chain Data Protocol (CDP).

Regardless of the differences among protocols, rules specifications and governance mechanics of these networks, a usage of the CrossCurve Token Bridge makes it possible for users to move assets among these chains in a reliable and secure way.

Mechanics

The CrossCurve Token Bridge consists of the Portal and Synthesis smart contracts deployed in each of the Blockchains: 1, 2, 3, and uses the CrossCurve Cross-chain Data Protocol (CDP) to transfer cross-chain calls between them.

To move assets across Blockchains, the CrossCurve Token Bridge uses synthetic assets (s-tokens). S-tokens are created when someone needs to transfer an asset between two blockchains.

Example: Native Token Bridging

Example of bridge with native tokens

When transferring token X, the bridge uses a Lock-Mint-Burn-Unlock mechanism. The original X token is locked in the Portal smart contract on Blockchain 1. This transaction triggers an event in the bridge smart contract, which is monitored by the Consensus Bridge.

The Consensus Bridge uses multiple messaging protocols to transmit the event to Blockchain 2. Once a sufficient number of confirmations are received from messaging protocols, the synthetic token sX is minted in the destination blockchain.

Example: Synth Token Transfer Without Portal

Example how bridge Synth tokens to other chain without use Portal

When transferring a synthetic token sX, the bridge uses a Mint-Burn mechanism. The original sX token is sent to the Synthesis smart contract on Blockchain 1, triggering an event in the bridge contract.

The Consensus Bridge sends the message to Blockchain 2 through multiple messaging protocols. Once enough confirmations are gathered, a new instance of the same sX token is minted on Blockchain 2.

Example in Practice

Let’s consider Bob transferring X token from Blockchain 1 to Blockchain 2. The process works as follows:

  1. Bob sends a transaction to the CrossCurve Token Bridge.

  2. The original X token is locked in the Portal smart contract on Blockchain 1.

  3. This triggers an event in the bridge contract, which is tracked and processed by the Consensus Bridge.

  4. The Consensus Bridge uses multiple messaging protocols to independently relay the event to Blockchain 2.

  5. Once enough confirmations are collected, the sX token is minted in Blockchain 2.

In our example, Bob’s transaction activates the Synthesis contract in Blockchain 2, which issues the synthetic sX token, backed by the X token locked in Blockchain 1.

At any time, Bob can initiate a reverse conversion to retrieve the original X token.

Transaction history

Transferring tokens from one blockchain to another using the CrossCurve Token Bridge is a complex cross-chain operation. The user can track its execution in the interface in real time.

Security

Only tokens whose smart contracts have been thoroughly audited by the CrossCurve team are added to the CrossCurve Token Bridge. The audit takes into account many characteristics of the project, and also examines the code of smart contracts for the presence of logic for moving and locking user tokens, which potentially creates a danger to user funds. Only tokens whose code complies with all security rules are allowed to be moved.

CrossCurve Pools v2

Introduction

CrossCurve Pools v2 is an advanced pool system designed to optimize cross-chain liquidity management within the СrossCurve MetaLayer. The system works with three primary asset types: USD-, ETH- and BTC-pegged tokens, which are issued by various projects across different networks. In the hubchain, a set of paired pools is created for each of these asset types. Each pool corresponds to a specific direction (blockchain) and functions as a bridge to that network.

Pool Structure

Each paired pool in the hubchain consists of two tokens:

  • Universal token - an asset from Sonic, common across all pools of the same type (xfrxUSD for USD assets, xfrxETH for ETH, and scBTC for BTC).

  • Synthetic derivative, backed by the original asset locked in the Consensus Bridge. This can include both single assets and Curve LP tokens.

Cross-Chain Transfer Process

CrossCurve Pools v2 enables asset transfers between blockchains in four stages:

  1. Bridge from the source network: The original token is locked in the Consensus Bridge in the source network, and the Consensus Bridge then mints a synthetic token (derivative) in the Sonic network.

  2. Exchange for the universal token: The synthetic token is exchanged for the universal token of the hubchain.

  3. Exchange for the destination synthetic token: The universal token is exchanged for a synthetic token corresponding to the target blockchain.

  4. Bridge to the destination network: The synthetic token is burned in the Consensus Bridge on Sonic, and the Consensus Bridge then unlocks the original token in the destination network.

Advantages Compared to the Previous System

The previous pool system used Curve stable pools with 8 assets, connected via liquidity provider (LP) tokens from one or more pools. CrossCurve MetaLayer introduces a fundamentally new approach — liquidity isolation, where each pool contains liquidity only for a single direction. This design delivers the following benefits:

1. Targeted Incentives

In the previous system, incentives directed into a pool were distributed across all 8 directions, reducing their effectiveness. In paired pools, blockchains can direct incentives exclusively into their own pool, increasing liquidity in that direction and improving bridge conditions for users.

2. Reduced Slippage

In Curve stable pools, increasing the number of tokens in a pool leads to higher slippage under imbalance. A 2-token pool shows significantly less slippage compared to an 8-token one under the same imbalance. Additionally, in the old system, a significant imbalance in one token increased slippage for all 8 directions, while in paired pools, slippage growth is confined to an affected direction only.

3. Improved Liquidity Efficiency

To minimize slippage in the previous system, equal liquidity was required across all 8 directions, which was inefficient for less active ones. Paired pools allow using smaller amounts of liquidity for lower-demand directions while maintaining the same slippage level, thus optimizing liquidity utilization.

4. Lower Risk During Depegs

A depeg – where an asset drops in value relative to its underlying – is a common occurrence. In multi-asset pools within a single network, a depeg can have wide-reaching consequences for all connected networks, leading to a liquidity drain across all tokens in the pool. For example, in the previous system, if one asset dropped to zero in value while each had $100,000 in liquidity, the total loss across the remaining directions could reach up to $700,000.

In CrossCurve MetaLayer’s isolated pools, a depeg from one blockchain affects only a single pool. In the same scenario, losses would be capped at $100,000. The system automatically pauses the affected direction when a depeg is detected (based on price deviation), preventing further risks. However, a pool with the synthetic derivative of the depegged token remains in the hubchain until the price stabilizes.

CrossCurve Oracle Network

Introduction

The CrossCurve Oracle Network is a cross-chain messaging service based on BLS signatures. It is a core subsystem of the CrossCurve Token Bridge as well as one of the supported messaging services used within the CrossCurve Token Bridge.

Cross-chain bridges are an attractive target for attackers because the message transmission layer effectively exists outside the onchain execution of both blockchains. In practice, vulnerabilities in traditional bridges are frequent and are almost always related to some form of centralization. A modern alternative is a decentralized cross-chain messaging service that relies on oracle networks secured with BLS cryptography.

Solution architecture

A network of independent oracles is a decentralized set of validators that:

  • Monitor events on the source chain (Ethereum, Polygon, Avalanche, and others)

  • Reach consensus on observed events

  • Collectively sign proofs for the destination chain

BLS (Boneh-Lynn-Shacham) signatures form the cryptographic foundation and allow the system to:

  • Aggregate signatures from many nodes into a single compact signature

  • Verify the authenticity of a group signature without revealing individual signatures

  • Reduce gas costs on destination blockchains thanks to signature compactness

How it works: a three-step process

1. Event listening

Oracles independently monitor smart contracts on the source chain. When a relevant event is detected, such as a cross-chain message being emitted, each node:

  • Verifies the correctness of the event

  • Generates a cryptographic proof (Merkle proof)

  • Signs it with its BLS private key

2. Signature aggregation

The current coordinator collects signatures from network participants:

  • Checks that the minimum signing threshold is met

  • Aggregates individual BLS signatures into a single multisignature

  • Prepares the data package for submission to the destination chain

3. Verification on the destination chain

A smart contract on the destination chain:

  • Receives the aggregated BLS signature and event data

  • Verifies the signature against the known group public key of the oracle network

  • Upon successful verification, delivers the original message to the target address on the destination chain

Advantages of the approach

Security: an attack requires compromising a threshold number of nodes Efficiency: a single multisignature verification instead of N individual checks Decentralization: no single point of failure

MetaLayer API

MetaLayer API is a unified interface for accessing distributed liquidity across the entire DeFi ecosystem. Unlike standard bridges or aggregators, the MetaLayer acts as an orchestrator by combining liquidity from DEXs aggregators and bridging into a single intelligent routing layer.

For fintech providers, this is the shortest path to integrating crypto functionality without the need to maintain dozens of separate protocols or spend resources on complex backend infrastructure.

Overview

At the core of the MetaLayer is the principle of complexity abstraction. Instead of manually integrating 10 bridges, 20 DEX aggregators or multiple aggregators, you connect to a single API that builds optimal routes on top of existing protocols.

Key benefits for businesses:

  • Unique routes: Access to multi-step exchange paths (e.g. swap on Chain A, then bridge, then swap on Chain B) that are not available via direct integrations

  • Maximum liquidity: Automatic selection of the best price across all connected liquidity sources

  • Flexible monetization: Tools for dynamic fee management and automated revenue distribution

Monetization and partnership

The CrossCurve MetaLayer is designed around a partnership-driven model. Activation of commercial terms consists of two stages:

Agreement on revenue share terms

Before going live, you need to contact our partnership team at a.gluhovskij@eywa.fi or @Eywa_COO. The manager will work out your specific revenue sharing terms with you and activate your API key for withdrawing accumulated fees.

Dynamic partner fees

You have full control over your margin. In each quote request, you can include the partnerFeeBps parameter.

  • Flexibility: Set different fees for different asset types or swap directions.

  • Calculation: 1 basis point (bps) equals 0.01%. For example, a value of 50 bps corresponds to a 0.5% fee.

  • Automation: The system automatically calculates the fee amount and includes it in the final quote for the user.

Quick start

API key and fee address

You can test the API without a dedicated key. In this mode, you cannot set or receive additional fees.

Contact a.gluhovskij@eywa.fi or @Eywa_COO to obtain an API key and register your EVM address. Your fees will be sent to this address.

Action flow for executing a swap

Step 1: Request routes

Your application requests possible transfer routes from network A to network B.

Step 2: Select route and build transaction

API returns options with the estimated time, fees, and output amount. Your application selects the best one.

Then, build the transaction with the selected route.

Step 3: Send transaction

User sends the signed transaction using ethers.js or any Web3 library.

Step 4: Track transaction status

Your application may monitor the transaction status across chains via REST API or WebSocket Monitor.

Step 5: Completion

Transfer completes in the destination network. All confirmation and relay logic is handled by MetaLayer infrastructure.

Overview of CrossCurve DAO

CrossCurve DAO — is a democratic, transparent, and decentralized organization that makes strategic decisions, engages participants, and incentivizes their contributions.

The goal of CrossCurve DAO is to create long-term incentives for attracting sustainable cross-chain liquidity, as well as to accumulate and manage the protocol’s own liquidity to ensure better conditions for cross-chain swaps in the market.

DAO governance is based on locking the EYWA governance token into veEYWA, which grants voting power. This voting power allows veEYWA holders to participate in decision-making, receive incentives, and earn income from EYWA protocols.


Advantages of veEYWA

Locking EYWA provides you with the following benefits:

  • Staking income

  • Voting rights and participation in DAO decision-making

  • Incentive earnings when voting for pools

  • Increased rewards for providing liquidity

  • A share of the platform’s fee revenue


Locking EYWA (veEYWA)

veEYWA stands for vote-escrowed EYWA. Users can lock their EYWA tokens for a maximum of 3 years, in exchange for veEYWA. The amount of veEYWA decreases linearly as the chosen lock duration elapses. veEYWA cannot be transferred directly, but can be transferred within an EYWA DAO NFT. The longer you lock, the more veEYWA you receive. For details, please see the lock formula, but the simple explanation is:

  • 1 EYWA, locked for 3 years = 1 veEYWA

  • 1 EYWA, locked for 2 years = 0.66(6) veEYWA

  • 1 EYWA, locked for 1.5 years = 0.5 veEYWA

  • 1 EYWA, locked for 1 year = 0.33(3) veEYWA

The longer you lock your EYWA, the greater your voting power (expressed in veEYWA) and the higher the boost you can achieve.


NFT Boosts

Owning an EYWA NFT can affect the amount of veEYWA you receive and, therefore, your voting power. An NFT’s rarity is determined by two parameters - MV (multiplier for veEYWA), a multiplier applied to the veEYWA you receive; as well as CT (Capacity per NFT), the maximum number of EYWA tokens affected by the NFT’s influence. Check the table below for the characteristics of each rarity level:

Rarity
Multiplier for veEYWA (MV)
Capacity per NFT (CT)

common

1.006

500

uncommon

1.036

3 000

rare

1.3

25 000

legendary

2.8

250 000

infinity

3

1 500 000

EYWA NFTs enhance your DAO voting power, increase returns from staking, incentives, and fees, and allow trading of locked tokens. They also attract investors due to their rarity and functionality.

Here are some ways EYWA tokens benefit different types of users:

For veEYWA holders - those who have locked their tokens to gain voting power:

  • Boosts voting power when making DAO decisions

  • Boosts the voting power that can be exchanged for incentives (to distribute EYWA inflation across CrossCurve pool gauges)

  • Boosts staking income for veEYWA holders

  • Boosts the voting power used for distributing $EYWA in CrossCurve pools

  • Boosts income from distributing the protocol’s fee revenue among veEYWA holders


Staking Income

Staking income is the reward for long-term holding and locking of EYWA tokens. The longer and larger the locked amount, the higher your staking rewards, which are credited at the end of each epoch.

Also, staking yield depends on the total volume of locked EYWA: the more tokens locked, the lower the yield.

You can view the detailed calculations at the following link.

Using EYWA DAO NFT further increases your staking earnings.


Voting Rights and DAO Decision-Making

CrossCurve DAO functions include:

  1. Managing protocol contracts: bridges, new networks, contract deployments, fees, and permissions.

  2. Managing the DAO treasury: inflation (amount and rate), incentives for community development, expenses to attract customers and partners, emission to bonds, gauges, and grants.

All of these functions are carried out through voting.

CrossCurve DAO voting is divided into three main categories. Core voting affects the calculation of the voting coefficient for distributing staking rewards.

Core voting addresses:

  • Changes/additions to DAO, CrossCurve, and EYWA functionality;

  • Incentives;

  • Inflation and directives;

  • Bonds;

  • Grants;

  • Gauges.

Other voting topics:

  • Incentive proposals;

  • Incentive directions;

  • Gauge listings.

Miscellaneous votings:

Votings not included in the categories above.


Increased Rewards for Providing Liquidity (up to x2.5)

CrossCurve DAO allows certain pools to receive additional rewards from $EYWA token emissions.

When $EYWA emissions are allocated to a pool, the interface displays a range of possible APR that users can earn by staking their LP position.

The final APR boost depends on the user’s voting power (formed by locking veEYWA) and the ratio of your liquidity to the total liquidity, taking into account other participants’ boosts in a specific pool. A maximum boost can increase your yield by up to 2.5 times.

Thus, holding veEYWA allows you to achieve higher returns when providing liquidity. Using EYWA DAO NFT further increases your yield boost in these pools.


Voting for Pools and Receiving Incentives (Bribes)

Locking EYWA tokens provides unique opportunities for additional income through receiving incentives for voting on certain pools. By voting, veEYWA holders determine the distribution of liquidity and rewards among CrossCurve pools. Projects seeking to attract liquidity offer veEYWA holders incentives (various tokens) in exchange for votes in their favor.

Locking EYWA turns voting rights into a source of income: veEYWA holders choose the most profitable offers and receive rewards in tokens, cryptocurrencies, or other forms of income from the projects. The higher your veEYWA balance, the more profit opportunities you have.

Using EYWA DAO NFT further increases your earnings when voting for pools.

Staking mechanics

Staking is the process of locking coins for a certain period, making them unavailable for trading. This mechanism supports decentralization and provides rewards to participants.

In the CrossCurve protocol, staking involves locking tokens in the DAO locker. Rewards are accrued every epoch and are tied to each user’s EYWA DAO NFT. Accrual occurs at the start of the new epoch for the previous one. In CrossCurve DAO, the epoch length is one week, with the end of the epoch at Wednesday 24:00 UTC and the start of the epoch at Thursday 00:00 UTC.

By using the “Compound” transaction, a user can add the earned rewards to the corresponding EYWA DAO NFT, in order to add them to the principal of your position and earn compound interest.


More details on reward calculations per epoch are provided below.

Distribution of Rewards Among DAO Participants

Each epoch, a fixed number of EYWA tokens (), is allocated for DAO participant rewards. This amount depends only on the total number of locked EYWA tokens in that epoch. All calculations, including the number of locked tokens and the calculated veEYWA, are performed at the end of the epoch. The allocated rewards are then distributed among participants proportionally to their share of veEYWA.


Algorithm for Calculating Rbase at the Start of DAO Operations

  1. Calculating the ratio of all locked EYWA tokens in this epoch to the total possible volume of EYWA tokens (1,000,000,000):

RatioLockedEYWA=VLockedEYWA1000000000Ratio_{Locked EYWA} = \frac{V_{Locked EYWA}}{1 000 000 000}RatioLockedEYWA​=1000000000VLockedEYWA​​
  1. If is less than 0.14, then is calculated as:

Rbase=RatioLockedEYWA∗i∗Inflation+Inflation∗0.01R_{base} = Ratio_{Locked EYWA}*i*Inflation+Inflation*0.01Rbase​=RatioLockedEYWA​∗i∗Inflation+Inflation∗0.01

, where

i=(3−RatioLockedEYWA∗9)i = (3-Ratio_{Locked EYWA}*9)i=(3−RatioLockedEYWA​∗9)

Inflation - the emission amount in the calculation epoch.

  1. If is greater than or equal to 0.14, then is calculated as:

Rbase=RatioLockedEYWA∗i∗Inflation+Inflation∗0.18752R_{base} = Ratio_{Locked EYWA}*i*Inflation+Inflation*0.18752Rbase​=RatioLockedEYWA​∗i∗Inflation+Inflation∗0.18752

, where

i=(0.5−RatioLockedEYWA∗0.2)i= (0.5 - Ratio_{Locked EYWA}*0.2)i=(0.5−RatioLockedEYWA​∗0.2)

Inflation - the emission amount in the calculation epoch.

All numerical coefficients indicated in the formulas are current at the time of DAO launch. They can be changed by DAO participants via voting.


Staking APY Table with 10 Million Locked Tokens Increments

For convenience, we have prepared tables with results grouped by different levels of locked token amounts.


Distribution of Rewards Among DAO Participants

After determining the total amount for all users (), it is distributed among DAO participants proportionally to the amount of veEYWA each participants holds.

RUserBase=LuserLall∗RbaseR_{User Base} = \frac{L_{user}}{L_{all}}*R_{base}RUserBase​=Lall​Luser​​∗Rbase​

, where

- the user’s veEYWA,

- the total veEYWA of all users,

- the total reward allocated to all participants.

NFTs

CrossCurve DAO NFT

EYWA DAO NFT is an ERC-721 NFT created when EYWA tokens are locked in the Locker.

Key features:

  • Attaching assets: Each EYWA DAO NFT can have EYWA tokens, Vesting Safes, and other EYWA NFTs attached to it.

  • Obtaining veEYWA: The obtained veEYWA is automatically tired to the corresponding EYWA DAO NFT.

  • Multiple ownership: A user can own an unlimited number of EYWA DAO NFT.

  • Summation of veEYWA: The total amount of a user’s veEYWA is equal to the sum of the veEYWA of all their EYWA DAO NFTs.

Thus, EYWA DAO NFT serves as a hub for managing your locked assets and voting power in the DAO, providing flexibility and scalability in project governance.


Creating an EYWA DAO NFT

When creating an EYWA DAO NFT in the Locker, you can lock EYWA tokens in various states When transferring to the Locker:

  1. EYWA tokens (standard ERC-20)

  • Ownership is transferred to the Locker contract.

  1. Vesting Safe contracts with direct ownership (held in the user’s wallet)

  • Ownership of the Vesting Safe contract is transferred to the Locker.

  1. Vesting Safe contracts with ownership via an NFT (Vesting Safe contracts attached to an EYWA NFT)

  • The Vesting Safe is detached from an EYWA NFT and transferred to the Locker.

  • The EYWA NFT ownership is also transferred to the Locker.

  1. ERC-20 EYWA tokens with ownership via an NFT (EYWA tokens attached to an EYWA NFT)

  • Tokens are detached from an EYWA NFT and transferred to the Locker.

  • Ownership of an EYWA NFT is also transferred to the Locker.

Calculating veEYWA:

The Locker calculates the amount of veEYWA based on the total number of EYWA tokens locked, including both standard ERC-20 tokens and those in the Vesting Safe.

Restrictions when creating an EYWA DAO NFT

  • You cannot create an EYWA DAO NFT by adding an empty EYWA NFT to the Locker.

  • You can attach no more than 100 Vesting Safes and 100 EYWA NFTs to one EYWA DAO NFT.


Modifying an EYWA DAO NFT

You can modify an EYWA DAO NFT in several ways:

Adding additional EYWA tokens:

  • You can lock more EYWA tokens in any of the ways described above at the time of creating an EYWA DAO NFT.

Adding/attaching empty EYWA NFTs:

  • You can attach additional empty EYWA NFTs to an existing EYWA DAO NFT.

Removing/detaching EYWA NFTs:

  • You can detach an EYWA NFT from an EYWA DAO NFT, returning them to the user’s ownership.

Extending the lock duration of tokens:

  • You can extend the lock duration of already locked EYWA tokens to increase voting power.

Providing Liquidity to CrossCurve Pools

Types of Liquidity Pools

CrossCurve offers two distinct types of pools, each with unique features and earning opportunities.

Stable Pools

Stable pools are designed for assets whose prices are pegged to each other:

  • Examples: Stablecoin pairs, such as USDT/USDC

  • Derivative Assets: Pairs like wstETH/rETH are also considered stable since their relative prices do not fluctuate significantly

  • Goal: Maintain an exchange rate of 1:1 between assets as accurately as possible

  • Features: Minimal slippage and stable exchange prices due to a specialized AMM formula

Stable pools are optimized for trading correlated assets with minimal losses and slippage, making them attractive to conservative investors.

Volatility Pools

Volatility pools are intended for pairs of assets with fluctuating prices:

  • Examples: USDT/EYWA, ETH/BTC and other uncorrelated assets

  • Formation: Created by combining heterogeneous assets

  • Protection: Utilize Curve's unique mechanism to mitigate impermanent loss

  • Features: Higher risk but potentially higher returns

Volatility pools are suitable for investors willing to accept higher risks in exchange for potentially higher returns.

Liquidity Provision Process

Adding Liquidity

CrossCurve offers two modes for adding/removing liquidity:

1. Easy Mode

  • Allows adding or removing funds with a single asset

  • Simplifies the process for beginners

  • Automatically handles all necessary conversions and transactions

2. via Curve (Balanced)

  • Designed for adding large sums

  • Requires balanced addition of assets to optimize yield

  • Minimizes slippage losses

Importance of Pool Balancing

When working with liquidity pools, it's essential to understand the concept of balance:

  • An ideally balanced pool has an equal percentage distribution of all assets

  • For instance, in a xCRVUSDC pool with six s-tokens, the optimal share for each asset is 16.6% of the total TVL

  • Adding an underrepresented asset (share <16.6%) earns an additional bonus

  • Adding an overrepresented asset (share >16.6%) results in losses

Ways to Earn When Providing Liquidity

1. Trading fees

The primary income source for liquidity providers is the trading fees from swaps occurring within the pool:

  • Fees are automatically distributed among all liquidity providers

  • The amount of fees received is proportional to your pool share

2. Farming and Additional Rewards

In addition to trading fees, liquidity providers may receive extra incentives:

  • EYWA inflation allocated by CrossCurve DAO voting as an incentive to attract liquidity

  • Other tokens added by external projects to attract liquidity

  • Increased rewards for veEYWA holders (vote-escrowed EYWA)

  • Points for participating in external project programs

3. Access to StakeDAO and Convex Strategies for Enhanced Yields

  • Obtaining higher yields by placing funds into CrossCurve pools through strategies within “Curve Wars” protocols, such as Convex or StakeDAO

4. Cross-chain Capabilities

CrossCurve's unique advantage is its ability to manage liquidity across different blockchains:

  • Liquidity providers can add and withdraw liquidity from all available networks

  • Liquidity providers can swap LP tokens across networks without impermanent loss

  • The ability to quickly and cost-effectively move funds in search of higher yields

Yield Optimization

To maximize yields when providing liquidity, it's recommended to:

  • Analyze pool conditions before adding liquidity

  • Select the optimal mode:

    • Easy Mode for small amounts and beginners

    • Balanced mode for larger sums and experienced users

  • Monitor pool balance when adding or removing liquidity to earn bonuses rather than incur penalties due to pool imbalances

  • Combine with EYWA locking to obtain additional rewards through yield boosts

  • Participate in voting for liquidity distribution between polls and vote for your pool (if beneficial, considering other opportunities for selling votes)

Conclusion

Providing liquidity on CrossCurve is a powerful earning tool in DeFi. The platform combines Curve Finance's proven reliability with CrossCurve's innovative cross-chain technologies, ensuring user security, convenience, and potentially high returns.

It’s crucial to remember that liquidity provision always entails certain risks; thus, it’s advisable to carefully study pool mechanisms and yield optimization strategies before making significant investments.

Voting for Incentives

Voting in CrossCurve is more than just participation in governance; it is an effective tool for generating additional income. Your voting power (veEYWA) becomes a valuable asset capable of producing returns alongside basic staking rewards.

How Voting Generates Income

By locking EYWA tokens, you receive veEYWA—voting power that:

  • Grants the right to influence liquidity distribution between pools

  • Allows support for projects offering additional rewards

  • Creates an additional income stream beyond basic staking

Important: The more veEYWA you hold, the higher the potential earnings from voting. Projects aiming to attract liquidity to their pools offer incentives in various tokens in exchange for your support in voting.

Sources of Income from Voting

1. Direct Incentives from Projects

Different projects compete for your support, offering their tokens as incentives for your votes:

  • Additional token payouts occur each epoch

  • Opportunity to receive tokens from promising projects. Selling immediately or holding onto them is your choice.

2. Monetizing Voting Power through NFTs

A unique CrossCurve advantage is monetizing your voting power by selling EYWA DAO NFTs:

  • Vote Selling: Although the veEYWA tokens themselves cannot be transferred directly, you can sell NFTs containing your voting power on the secondary.

  • Pricing: NFT value directly correlates with the amount of veEYWA contained and potential income from voting.

  • Liquidity of Locked Assets: Option to sell voting power without waiting for the lock period to end.

Given the limited issuance of veEYWA, their value could increase, enhancing the worth of your voting NFTs and creating a third revenue stream.

Strategies for Maximizing Voting Profits

Monitoring High-Incentive Offers

Track projects offering the largest rewards for voting. Analyze proposals, selecting those providing an optimal balance between:

  • Reward size

  • Project stability

  • Token growth potential

Or delegate this task to professionals via CrossCurve's website interface. (This feature will be available soon)

Combining with NFT Boosters

Strengthen your voting power through EYWA NFTs:

  • More veEYWA = more votes = higher rewards

  • Legendary or Infinity level NFTs can increase voting returns by up to 2.8x and 3x respectively

Active Management of Voting Assets

Regularly participate in votes to avoid idle veEYWA:

  • Unused votes yield no extra profits (delegate or remember to vote yourself)

  • Monetize your voting power by selling NFTs when necessary

  • Reinvest tokens received from voting into staking to leverage compound interest

Conclusion

Voting in CrossCurve is not merely a bureaucratic function but a tangible opportunity to gain additional income, influence the evolution of DeFi, and actively participate in a growing community.

Migration to Sonic

Why are we moving to Sonic

CrossCurve is moving to Sonic

We have made a strategic decision to migrate CrossCurve's hub chain from Fantom (FTM) to Sonic. This is not just a network change - it’s a transition to a new level of speed, efficiency, and possibilities. Let's explore why Sonic is the optimal choice, what benefits it brings to users, and how this step will shape our future.

Why are we moving to Sonic?

1. Game-changing speed

Sonic dramatically accelerates blockchain operations. The average transaction finalization time is just 720 milliseconds.

For comparison:

  • Ethereum — ~12 seconds

  • Fantom Opera — ~1-2 seconds

This makes Sonic one of the fastest EVM-compatible blockchains. In DeFi, speed is critical: minimal latency reduces arbitrage risks, improves liquidity conditions, and enhances user experience.

Sonic brings blockchain interactions closer to Web2 performance—transactions process instantly, while fees remain minimal.

2. An economic model that rewards projects

Most blockchains either burn fees or direct them to network funds. Sonic takes a different approach:

  • Up to 90% of fees are returned to developers

  • Projects generate sustainable revenue without raising fees

  • Liquidity is redistributed to benefit everyone: users, developers, and token holders

The more activity in the network, the higher the protocol revenues and user incentives.

3. Simple migration and ecosystem support

Sonic is an evolution of Fantom’s technology but with enhanced features.

What does this mean for projects?

  • Easy migration — smart contract code requires minimal changes

  • $120M support fund — Fantom has allocated grants to migrate dApps to Sonic

  • Major centralized exchanges have integrated automatic FTM → Sonic (S) swaps

We gain all the advantages of the new network without losing functionality or liquidity.

Why is Sonic better than other blockchains?

1. ve(3,3) Flywheel: a powerful tokenomics model

Sonic’s economy is built on the ve(3,3) concept, which incentivizes staking, liquidity, and long-term token holding.

This model has already proven successful in Curve, Solidly and Velodrome, creating a sustainable DeFi cycle.

2. Leading DeFi projects are moving to Sonic

Sonic has already attracted top players, including:

  • AAVE — a leading DeFi protocol managing $10B+ in assets

  • Curve — the largest stablecoin exchange platform

  • Solidly and other major DeFi projects — key players in the industry

This means liquidity and users are already migrating to Sonic, making participation in this ecosystem strategically important.

3. Full Ethereum compatibility

Sonic supports EVM, making it fully compatible with existing Ethereum and Fantom smart contracts.

А Sonic Gateway — a native bridge enabling secure asset transfers between Ethereum and Sonic without reliance on centralized solutions.

Conclusion

CrossCurve’s transition to Sonic is not just an upgrade - it’s a leap forward in technology.

What are the key benefits?

  • 720ms transactions — faster than any other EVM blockchain

  • Up to 90% of fees returned to developers — projects earn more

  • Seamless migration with $120M support — transition risks minimized.

  • Top DeFi projects onboarded — Sonic’s ecosystem is growing rapidly

Sonic Upgrade Stages

Migrating the hubchain to Sonic is a major system upgrade affecting the protocol’s architecture, mechanics, and economy. The principles of working with liquidity are changing, system resilience is increasing, and new earning opportunities are opening up for CrossCurve users. Below are the key stages of this transition:

1. Deployment of Pools on Sonic✅

Pools based on a new architecture—isolated pair pools—are being launched on Sonic. Previously, large multichain pools were used, combining up to 8 blockchains with synthetic derivatives. Now, each pool includes only the liquidity of one isolated blockchain and the hubchain – in this case, the liquid tokens of the Sonic blockchain.

This approach enhances the system’s overall resilience and reduces imbalance risks. Individually, the pools will be less liquid, but the overall architecture will provide greater flexibility, resilience, and potentially higher returns for liquidity providers.

2. Whitelisting on Curve and Activation of CRV Incentives✅

We are initiating a voting process in the Curve DAO to get whitelisted and connect the pools to protocol reward distribution. This will allow us to activate CRV incentives for our pools and increase yields for our liquidity providers. Since the voting takes about two weeks, we are starting the process in advance to launch reward distribution as quickly as possible after migrating our hubchain.

3. Connecting Sonic Pools to Routing

After deployment and basic setup, the Sonic pools will be connected to our routing system. At this stage, swaps through the new pools in Sonic will become available to CrossCurve users. To ensure a seamless transition, Sonic and Fantom pools will operate in parallel, allowing liquidity to flow between them without interrupting system functionality.

4. Activation of CrossCurve DAO Incentives on New Pools✅

After launching the pools and connecting them to the infrastructure, we will activate incentives from CrossCurve DAO – our first step in attracting liquidity to the new Sonic pools. External projects will be able to offer rewards to CrossCurve DAO participants in exchange for votes on specific liquidity pools, allowing users to start earning right away.

5 Connecting Sonic Gems to Incentives on Fantom Pools✅

As Sapphire-tier winners in the Sonic Boom program, we possess special airdrop points called Gems. These are distributed among applications based on product metrics and activity. We will direct all of them toward incentivizing liquidity in our pools in the form of the cmGEMS1 token, using it as a reward distribution mechanism within the protocol.


WE ARE HERE


6. Disabling Incentives on Fantom Pools

As incentives are activated on Sonic pools, they will simultaneously be disabled on Fantom. However, CRV rewards will continue to be distributed for some time after deactivation due to the mechanics of Curve.

7. Disconnecting Fantom Pools from Routing

After most of the liquidity has been migrated to Sonic, Fantom pools will be disconnected from the routing system. Swaps through them will no longer be possible; the pools will remain accessible for withdrawals only. It is especially important for CrossCurve users to move their assets before this stage to avoid high slippage, as the majority of liquidity will have already been relocated.

8. Connecting Sonic Points and Rings to New Pools

At this stage, the pools will start generating Sonic Points and Rings, allowing liquidity providers to participate in additional reward programs, including all future airdrops. Thanks to the new pool architecture, half of the liquidity will be concentrated in Sonic blockchain assets, enabling our users to earn even more incentives

9. Activation of $EYWA and $CRV Rewards via Votemarket

After completing the Curve vote and configuring campaigns on Votemarket, we will activate the reward distribution in $EYWA and $CRV tokens – thus completing the migration of our hubchain to Sonic and fully launching most of the economic incentives in the new pools.

Routing

Routing provides a convenient graphical representation of a cross-chain transaction, showing all the transitions and fees involved step-by-step:

Routing Details Legend

- Adding token to the pool

- Removing token from the pool

- Burning of synthetic token

- Receiving asset from the pool (LP or token obtained in exchange)

- Cross-network transition using lock/receive or burn/unlock mechanics

- Token exchange within the pool

- Unwrap the native token

- Wrap the native token

Operation Interruption

There are situations where a cross-chain operation may be interrupted:

  1. The operation is interrupted based on the Slippage condition. If, during the transaction execution in one of the pools, the slippage exceeds the upper limit set by the user, the transaction will be interrupted, and the intermediate tokens will be credited to the user's address on the network where the interruption occurred.

  2. The operation is interrupted because the cross-chain call cannot be executed. If the infrastructure facilitating cross-chain interaction fails to execute the cross-chain call, the operation will be interrupted.

The transaction interruption will be displayed as a message in the Transaction history, where the user will be provided with actions to handle the situation.

Slippage condition

Slippage condition

The operation is interrupted based on the Slippage condition.

If an interruption occurs in one of the pools in the cross-chain transaction chain due to the slippage condition, the tokens that were input into the pool will be credited to the sender's account, and the user will be prompted to continue the operation.

If an operation is interrupted in the Stable swap pool system due to the slippage condition, the user's account will be credited with s-tokens. These tokens are backed by crypto assets locked in Portal smart contracts on supported CLP networks. Through CrossCurve DEX, you can exchange these s-tokens for stablecoins or any other asset available for swapping (full list here).

Go to Transaction History and click Details next to the interrupted transaction.

To continue a transaction that failed due to a slippage error, click Continue operation.

After clicking the Continue operation button, the application will switch to the Continue operation mode. The difference between the Continue operation mode and Normal mode is that in the Continue operation mode, the User will be sent native tokens (if the User’s wallet doesn’t have the chain’s native token for completing the transaction) to pay the gas fee for continuing the transaction in the chain where the interruption occurred.

After pressing the button, the user will be taken to the Swap interface with preselected assets:

In the top FROM field, the "intermediate" tokens that were credited to the user's wallet on the network where the operation was interrupted will be selected.

In the bottom TO field, the desired asset that the user initially wanted to receive but the operation was interrupted will be selected.

Sequence of actions in the Continue operation mode window:

  • Review transaction details such as Slippage and exchange rate in the dropdown menu.

  • Give permission for the application to interact with the asset

  • Sign transaction.

If a User changes values in the Source field, the application will switch to the standard Swap mode and no native asset will be transferred to the user's account to pay for the gas.

Total Slippage is the total effective slippage applied across all networks where a swap occurred during a cross-chain transaction.

It is calculated as the sum of slippage percentages for each individual network involved in the transaction (details here).

The user will have one free attempt to continue the transaction with new fees and Slippage conditions. If for some reason you can not continue the operation, сontact support on Telegram / Discord and our support team will help you.

Liquidity Interface

Liquidity Section and its Functionality

To start working in the CrossCurve application, go to the Liquidity section, in the top right corner click “Connect wallet”, select a suitable wallet from the list and confirm the connection, making sure that you are on the original page https://app.crosscurve.fi/liquidity.

  1. After successfully connecting, in the Choose pool window, select the pool or asset you are interested in for working with liquidity.

Once you have chosen the necessary asset, the interface will display the TVL in the selected pool, as well as a link to the original pool of the selected asset on Curve.finance, your Wallet Balance showing the amount of the asset, and the Estimated APR for Farming in the selected pool.

  1. The next step is to select the operation to be performed with the asset (Deposit or Withdraw) and the method of execution, Balanced or Easy mode.

For convenience, a quick link to add the token to the wallet via the contract address has been added for correct balance display. By clicking on the “+”, a request will pop up to add a custom token. After signing, it will be displayed in the wallet.

Easy mode

In Easy mode the application allows you to unbalancely add (Deposit) or withdraw (Withdraw) funds into the Curve liquidity pool with a single asset (assets that are part of the LP token or the LP tokens themselves), saving time by performing complex operations (without interacting with the Curve interface) in one click.

Note that this method is not always advantageous due to the architecture features of Curve.

  1. After selecting the necessary operation (Deposit or Withdraw) in Easy mode and clicking next (Next),

choose the network (different networks available in the CrossCurve pools, depending on the pool selected. For our example, these are: Polygon, BNB Chain, Arbitrum, Optimism, Ethereum, Base, Avalanche, and Gnosis for the xSTABLE pool.) and the token you need.

  1. After entering the desired amount of tokens, the system will calculate the number of LP tokens received and the gas fee. By clicking Routing details, Routing will be displayed - this interface provides a convenient graphical representation of the cross-network transaction, showing all associated transitions and fees step by step.

  1. Slippage Settings. In the settings, you can specify slippage (by default, the parameter is set at 0.5%)

  1. The first transaction requires allowing the USD₮0 spending by clicking «Approve USD₮0» and signing the transaction in the wallet. To sign the transaction, you must hold the native token of the network in which the transaction is being made to pay for the gas.

  1. After confirming the spending of USD₮0, a “Swap” button will appear. By pressing the "Swap" button, a request will be sent to the wallet to confirm the transaction

  1. For convenience, a quick link to add the token to the wallet via the contract address has been added for correct balance display. By clicking on the “+”, a request will pop up to add a custom token. After signing, it will be displayed in the wallet.

There is also a Balanced method of adding liquidity to the pool – you can use multiple assets so that your operation brings the pool into a balanced state.

This method should be applied to avoid losses/earn profit in cases where you work with large amounts relative to the total TVL of the pool, or when the pool is close to perfect balance.

via Curve (Balanced)

In Balanced mode the application allows adding liquidity (Deposit) in s-tokens or withdrawing (Withdraw) funds from s-tokens to the original assets of the EYWAUSDT, xCRV, xCRV2, CRV/USD, 3UNIT0, wFTMUSDC, CrossCurve frxUSD, CrossCurve frxETH, xsStable, xeWETH and xbBTC pools, CrossCurve liquidity pools with a single asset (assets that are part of the LP token or the LP tokens themselves), performing complex operations in one click.

However, it requires working with pools on Curve.

Part I Adding Liquidity

  1. After successfully connecting, in the Choose pool window, select the pool or asset you are interested in for working with liquidity.

  1. Next, select the operation to deposit (Deposit) and the Balanced method of execution.

Proceeding further by pressing Next, a step-by-step mini-guide will appear:

  • Check the liquidity pool on Curve to find the most profitable strategy

  • Obtain the necessary s-tokens here on CrossCurve

  • Deposit liquidity in a balanced way and earn additional income on Curve

  1. Follow the step-by-step mini-guide.

Part II Withdrawing Liquidity

  1. After successfully connecting, in the Choose pool window, select the pool or asset you are interested in for working with liquidity.

  1. Next, choose the withdrawal (Withdraw) operation and the Balanced option.

Proceeding further by clicking Next, a step-by-step mini-guide will appear:

  • Check the liquidity pool on Curve to find the most profitable strategy

  • Withdraw liquidity in a balanced manner and earn additional income on Curve

  • Convert s-tokens into original assets in this window

  1. Follow the step-by-step mini-guide.

Liquidity provision use cases

Liquidity provision on CrossCurve offers the chance to contribute to the market stability of cross-chain assets. By staking tokens in liquidity pools like EYWAUSDT or CrossCurve frxUSD, providers earn trading fees from swaps occurring within the pool. This process not only provides a potential income stream through fees and rewards but also plays a crucial role in facilitating smooth cross-chain transactions.

Savvy investors can leverage CrossCurve's advanced AMM algorithms to balance risk and return, optimizing their positions in a multi-token ecosystem. Always consider the associated risks and conduct due diligence before participating.

👇 Learn how to deposit and withdraw liquidity from CrossCurve pools in the sections below. Use the sidebar for easy navigation between sections.

DepositWithdrawCurve Knowledge Database

Deposit

👇 Choose the mode to deposit your funds

Easy mode (Imbalanced)via Curve (Balanced)

Easy mode (Imbalanced)

Adding Liquidity

Example of using Easy mode for adding liquidity of the USD₮0 token into the xSTABLE LP token

To start working in the CrossCurve application, go to the Liquidity section. After successfully connecting your wallet, in the Choose pool window, select the xSTABLE pool. This mode allows you to exchange a single stablecoin into the liquidity token without interacting with the liquidity pool interface on Curve.

  1. Having selected the Deposit operation and Easy mode, proceed to the exchange modal window by pressing Next.

  1. Next, select the USD₮0 token (or any other available asset participating in the xSTABLE pool) to add the liquidity and choose the preferred network of the received original asset.

  1. After entering the desired amount of tokens, the system will calculate the number of LP tokens received and the gas fee. By clicking Routing details, Routing will be displayed - this interface provides a convenient graphical representation of the cross-network transaction, showing all associated transitions and fees step by step:

  1. The first transaction requires allowing the USD₮0 spending by clicking «Approve USD₮0» and signing the transaction in the wallet. To sign the transaction, you must hold the native token of the network in which the transaction is being made to pay for the gas.

After confirming the spending of USD₮0, a “Swap” button will appear.

  1. By pressing the "Swap" button, a request will be sent to the wallet to confirm the transaction of depositing the USD₮0 token into the xSTABLE pool on Curve.

  1. After signing the transaction, a notification about the sending, the ongoing exchange, and the estimated waiting time will be received. The status and progress will be displayed in the top right corner.

If in Easy mode you see high losses, consider other assets for acquisition or use the Balanced mode of liquidity deposit

via Curve (Balanced)

Adding liquidity to pools on SonicAdding liquidity to pools on Taiko

Withdraw

👇 Choose the mode to withdraw your funds

Easy mode (Imbalanced)via Curve (Balanced)

Curve Knowledge Database

"Curve Knowledge Database" is your comprehensive resource for all things related to Curve Finance.

🥽Dive into expert insights on Curve's unique AMM system, liquidity pools, staking strategies, and yield optimization techniques. Whether you're a beginner seeking basics or an advanced user exploring in-depth mechanics, this knowledge base is equipped with tutorials, FAQs, analytics, and community wisdom to guide your decentralized finance journey on Curve. Stay informed, stay ahead.

Balanced liquidity provisionGuide to transferring CRV from Fantom chain to Ethereum mainnetDisclamer

Balanced liquidity provision

Example of obtaining the av3CRV LP token from the avDAI/avUSDC/avUSDT CrossCurve pool.

Here is the pool address, and the list of supported tokens.

1. To start, go to the Curve Finance website via the link, or go to the Pools tab and enter the name of the pool you wish to find (avDAI/avUSDC/avUSDT) in the search bar. You need to select the network in which the liquidity pool is located where you want to deposit your tokens (liquidity). For this example, the Avalanche network will be used.

  1. On the pool page, connect your wallet to the site by clicking on "Connect Wallet".

3. Choose the installed wallet (or use Wallet Connect) and confirm the connection, making sure you are on the original page https://curve.finance.

4. On the pool page, interaction happens through the application highlighted in the screenshot; look for the Deposit tab.

5. In the Pool Details tab, pay attention to which tokens (DAI.e, USDC.e, and USDT.e stablecoins) are part of the pool.

The avDAI/avUSDC/avUSDT pool consists of three stablecoins; accordingly, the pool will be balanced if the share of each asset in the pool constitutes 100/3 = 33.3% of the total TVL of the pool. (more details here)

6. We will demonstrate a balanced method of adding liquidity to the pool – you can use multiple assets so that your operation brings the pool into a balanced state. This method should be applied to avoid penalties and earn additional profit from Curve in cases where you work with large amounts relative to the total TVL of the pool, or when the pool is close to perfect balance.

For balanced funding, in the Deposit tab, select "Add all coins in a balanced proportion" and the system will automatically distribute them in equal proportion. Indicating the amount, confirm spending (click on Approve Spending). In the Edit tab, you can edit the amount of funds available for spending (by default – unlimited)

7. After successful confirmation, you will see a green button labeled Spending Approved. Then, click on Deposit. After confirming the transaction, you will see a green Deposit Complete button, and the balance of av3CRV LP tokens will be displayed in the Your Details tab.

Guide to transferring CRV from Fantom chain to Ethereum mainnet

  1. Open the Curve DAO Token (CRV) contract in FTMScan:

https://ftmscan.com/token/0xe6c259bc0fce25b71fe95a00361d3878e16232c3?a=0xbcd3e2e841cc6140ede73c9ad8ad86ec7e423f52

  1. Go to the Contract tab, choose Write Contract, and connect your wallet by clicking Connect to Web3.

  1. Expand the approve submenu for the Curve DAO Token (CRV) contract and make sure the _spender address is the following bridge contract:

Enter the number of tokens to approve for moving (in Wei format, meaning that you need to add 18 zeroes to the end of the amount or click and choose the right format).

Here is an example for approving 10,000 CRV tokens:

  1. Click and sign the Token Approval transaction in your wallet.

  2. After a successful Token Approval transaction, find the Layer Zero Bridge contract for Curve DAO Token (CRV) in FTMScan:

https://ftmscan.com/address/0x7ce8aF75A9180B602445bE230860DDcb4cAc3E42

  1. Go to the Contract tab, then Read Contract.

  1. Click on the 1. quote tab, after which you will see the current Wei cost of the transfer. Click on that to open the converter. Copy the FTM (1) value.

  1. Go to the Write Contract tab and connect your wallet by clicking Connect to Web3.

  1. Click on the 1. bridge (0xc3de453d) tab, after which you’ll see a form with 3 fields to be filled out as follows:

  • In the bridge field, enter the value you copied from 1. quote.

  • In the _receiver (address), enter the receiving Ethereum address (your own, if sending to yourself).

  • In the _amount (uint256) field, enter the number of tokens (in Wei format: add 18 zeroes to the end of the amount or click and choose the right format).

Example of filling out the fields for transferring 10,000 CRV tokens:

Click and sign the Bridge transaction in your wallet. Your transfer has now been sent. You can find the status and other details of the transfer here: https://layerzeroscan.com/?srcChainKey[0]=fantom

Disclamer

Attention!

Curve pools are based on a specialized AMM formula for trading stablecoins with minimal slippage and stable prices. Differing from the standard AMM formula x * y = k, Curve applies a modification focusing on assets with similar prices, providing effective pricing and liquidity for closely correlated tokens. Pools are adapted to the market by adjusting the asset weights, allowing them to maintain stable exchange prices even with changing market volatility. Therefore, it is necessary to pay attention to the liquidity balance of each stablecoin in the Pool Details tab. Go to the original liquidity pool on Curve you are working with, and assess its balance. For example, let's consider the xCRVUSDC pool.

The xCRVUSDC pool consists of six s-tokens, so the pool will be balanced if the share of each asset in the pool constitutes 100/6 = 16.6% of the total TVL of the pool.

  1. If you add one asset to the pool, the share of which is less than 16.6%, you will receive an additional bonus for balancing the pool.

  1. If you add one asset to the pool, the share of which is greater than 16.6%, you will receive a penalty in the form of slippage because this operation worsens the pool balance.

  1. If you withdraw one asset from the pool, the share of which is less than 16.6%, you will receive a penalty in the form of slippage because this operation worsens the pool balance.

  1. If you withdraw one asset from the pool, the share of which is greater than 16.6%, you will receive a bonus because this operation balances the pool.

  1. It should be noted that this example is not a financial strategy, and the imbalanced Easy mode is not always profitable (for example, if the pool is balanced) and also depends on the liquidity volume you are working with: the higher your volume relative to the total TVL of the pool, the more likely it is that the imbalanced method will be disadvantageous and you should use the Balanced mode. To avoid high losses of funds, always consider these factors and the condition of the pool before making a decision about the operation.

Here is an example, how the volume of liquidity you work with can affect the final result when performing the operation.

DAO

Locker InterfaceVote InterfaceIncentives InterfaceProposals InterfaceWorking with the EYWA Locker contract in Arbiscan.

Incentives Interface

Incentives Interface Description

Incentives interface provides access to the ve(3,3) mechanism in the CrossCurve DAO for external projects and protocols, as well as for veEYWA holders.

«ve(3,3)» is a mechanism used in DeFi protocols that combines (3,3) from game theory (mutually beneficial cooperation) and ve (vote escrow, i.e., token locking for voting), creating a tokenomics model where everyone benefits from acting in the protocol’s best interests, generating overall synergy.

Now, owners of locked EYWA tokens (veEYWA) can receive additional rewards for participating in votes for specific liquidity pools, significantly expanding the earning opportunities within the ecosystem. Meanwhile, external projects can acquire liquidity, gain visibility, and secure their status in the cross-chain space.

To get started in the CrossCurve application, go to the Incentives page in the DAO section. Click “Connect wallet”, select a suitable wallet from the list, and confirm the connection, making sure you are on the official page: https://app.crosscurve.fi/incentives

On the Incentives page, detailed information will be displayed:

  • Current voting round ends in - remaining time until the voting period ends in this epoch

  • Farm pools - pool name and its statistics:

  • Basic Volatile - pool type*

* CrossCurve offers two distinct liquidity pools to users: the Stable Pool and the Volatility Pool.

Volatility Pools consist of liquidity (Curve pools) for asset pairs with volatile prices, typically experiencing divergence. For example, USDT vs. EYWA or ETH vs. BTC.

Volatile pairs are formed by combining uncorrelated assets and utilize Curve's unique impermanent loss compensation mechanism for pools containing volatile assets.

Stable Pools are pools of stable liquidity (Curve pools) between assets whose prices are pegged to each other. For example, USDT vs. USDC.

Another case involves derivative assets, such as wstETH and rETH. Although rETH is considered a volatile asset, the trading pair between wstETH and rETH is classified as a stable pool because the price of wstETH does not significantly fluctuate relative to rETH.

Stable pairs on CrossCurve are designed for correlated assets and aim to maintain a 1:1 transfer ratio between them as closely as possible.

  • Votes - number of veEYWA votes cast and the percentage of total votes received by this pool among all pools participating in the vote

  • Chain - the network in which the pool operates

  • TVL - total value locked in the pool

  • Volume (24h) - trading volume in the pool over 24 hours

  • APR - yield in the pool

  • Total incentives - total rewards allocated for the epoch in USD equivalent

Attention: The Incentives function is mainly used by protocols. Please ensure that you understand how it works before using it, as any transaction is final and cannot be reversed. For more detailed information, follow the Read docs link.

For easier navigation, use the filter icon to search for a specific network or token within a pool.

To propose a reward for all CrossCurve DAO participants in exchange for their votes in the next epoch, select the pool to which you want to allocate rewards. At the beginning of the next epoch, these rewards will be evenly distributed among all those who voted for that pool.

In the modal window that appears, select the token in which you want to add rewards and enter the amount to be allocated.

To proceed with adding the selected rewards to the pool, you must give consent by checking the box, as any transaction is final and cannot be reversed, meaning the allocated tokens cannot be refunded.

After confirming your agreement with the reward allocation terms, click Add Incentive and sign the transactions to approve spending (Approve) and add the rewards (Add Incentive)

By navigating to the Vote page in the DAO section, you can view the amount of allocated rewards for DAO participants in the current and upcoming epochs:

Estimated EYWA emission in the next epoch - average amount of rewards allocated for the next epoch in EYWA tokens

Estimated CRV emission in the next epoch - average amount of rewards allocated for the next epoch in CRV tokens

Estimated incentives available in the current epoch - average amount of rewards allocated for the current epoch in USD equivalent

The reward amounts allocated to voters for each pool are displayed in the Incentives column.

On the Dashboard page in your personal statistics, rewards are calculated in the Incentives section. At the end off the epoch, rewards become available for claiming. To claim your rewards, click Claim and sign the transaction(s) in your wallet.

Yield

Farms InterfaceAPR CalculatorEYWA pool via Convex

Staking liquidity and earning rewards

By providing liquidity in CrossCurve pools you can earn rewards in EYWA and/or CRV.

Staking LP-tokens

  1. After successfully connecting your wallet, you will see all available pools for staking LP tokens.

After selecting the desired liquidity pool and clicking “Lock LP and get rewards”, we will see a modal window for staking liquidity to earn EYWA and CRV.

After specifying the LP amount, click Approve EYWAUSDT and confirm spending of LP tokens by singing the transaction in your wallet.

Then click Stake, and sign the transaction in your wallet.

After the transaction is successfully completed, the balance of staked LP tokens will be displayed on the page of the pool where you locked the funds in the Staked section.

Unstaking LP Tokens

Unstake LP tokens by clicking Unstake.

After specifying the LP amount click Unstake and sign the transaction in the wallet.

Receiving rewards

For farming rewards in EYWA and CRV simultaneously, click Claim in all pools

Confirm the transaction in Your wallet.

Also you can go to the Merkl dashboard by clicking the link and claim the rewards manually

After successfully connecting your wallet, go to the Claim section and follow the instructions on the Merkl website.

APR Calculator

To get started with the CrossCurve app. navigate to the APR calculator page in the Yield section. Click Connect wallet, select the appropriate wallet from the list, and confirm the connection, ensuring you are on the official page: https://app.crosscurve.fi/farm?&calculator=1.

After successfully connecting to the wallet, select the desired pool from the list.

The application will display information about the selected pool:

Your vAPR - total APR in the pool including the boost

Pool TVL - The total value locked in the pool

Total veEYWA - The total amount of veEYWA

To calculate the required amount of veEYWA tokens for obtaining a boost, enter the desired amount of LP tokens for locking in the selected pool in the Your deposit field and adjust the slider to the desired boost level. The Your vAPR line will calculate the APR obtained with the selected boost.

After entering the amount of LP tokens to be locked and the desired boost, the application will calculate the required amount of veEYWA tokens to achieve the boost and the desired APR

Your vAPR - The projected APR with the selected boost

You have - The veEYWA balance in the connected wallet

Need for boost -The required amount of veEYWA to achieve the selected boost

To obtain the necessary amount of veEYWA tokens, use the Locker by clicking Get veEYWA for BOOST.

Vesting

Claim portal interfaceEarly farming program interface

Outdated

Early farming program

Pools/asset contracts

Hubchain Pools and Assets💱Supported tokens

Integration Guide

There are two approaches available for integrating with the CrossCurve MetaLayer service. Choose the one that best fits your tech stack and transaction control requirements.

Direct Integration with REST API

Use this method if you need full control over the process or are using a language other than TypeScript/JavaScript.

Simplified Integration with SDK

A client library designed for quick integration into JS/TS projects. It abstracts interaction with the MetaLayer API, provides type safety, and simplifies standard swap scenarios.

SDK methods

sdk.init()                              // Load chains and tokens

Swap Methods

sdk.getQuote(params)                    // Get best swap quote
sdk.executeQuote(quote, options)        // Execute swap
sdk.trackTransaction(id, options)       // Track status
sdk.recover(requestId, options)         // Manual recovery

Token/Chain Data

Advanced Swap Methods

Guide for Developers

Technical Documentation for CrossCurve DAO Smart Contracts

CalldataHelperV1DelegationManagerV1DelegationConditionValidatorV1EmissionManagerV1EscrowManagerEscrowVoteManagerV1GaugeFactoryV1GaugeV1IncentiveRewardsDistributorLockHolderFactoryV1LockHolderV1ProposalManagerRebaseRewardsDistributorV1RewardsDistributorFactoryV1Treasury
0x7ce8aF75A9180B602445bE230860DDcb4cAc3E42
sdk.chains                              // All supported chains
sdk.getTokens(chainId)                  // Tokens for chain
sdk.getToken(chainId, address)          // Single token
sdk.getChainByCaip2('eip155:42161')     // Chain by CAIP-2
// Routing
sdk.routing.scan(request)               // Get all available routes

// Transaction building
sdk.tx.create(request)                  // Build swap transaction
sdk.tx.createEmergency(requestId, sig)  // Emergency withdrawal tx
sdk.tx.createRetry(requestId, sig)      // Retry delivery tx

// Tracking
sdk.tracking.get(requestId)             // Get transaction status
sdk.tracking.search(query)              // Search by address/hash

// Inconsistency resolution
sdk.inconsistency.getParams(requestId)  // Get resolution params
sdk.inconsistency.create(request)       // Create resolution tx

CrossCurve Tokenomics

We present the new improved edition of CrossCurve tokenomics, developed in accordance with the recommendations of experts, auditors and advisors.

🔗 Full version of CrossCurve tokenomics is available in this spreadsheet

🎬 Initial circulation supply, FDV and initial market cap

Listing price: $0,07 Fully diluted valuation: $70 000 000 Market cap on TGE: $3 023 740 IMC (without liquidity): $921 539

After listing, the total circulating number of the Eywa tokens will be 43 196 286 (4,32% of the total supply). This figure represents the sum of the tokens unlocked on the community round, market-making tokens, airdrop, treasury and KOL tokens.

TGE mechanics

The TGE stage includes the following steps:

  1. The Eywa token smart contract will be deployed in Ethereum chain;

  2. The entire EYWA emission (1 billion tokens) will be issued and then transferred to the Arbitrum chain using the CrossCurve Token Bridge.

  3. The vesting contracts will be deployed in Arbitrum chain.

  4. EYWA is an omnichain token and can be moved to Arbitrum, BSC and Fantom chains.

  5. The CrossCurve team will send the Eywa token emission to the vesting contracts in accordance with the project’s tokenomics.

  6. Token distribution begins after Listing date in a special section on app.crosscurve.fi which will become available after the TGE. On TGE, users will be able to connect their wallets and access their personal vesting safes, linked to their addresses. During the vesting period, Eywa tokens are unlocked according to the scheme defined in tokenomics, and owners can transfer the unlocked tokens to their wallets.

  7. The Listing date will occur no later than 14 days after TGE.

🕐 Eywa token vesting rules

The CrossCurve tokenomics outline various user categories, each with different lockup periods. After the TGE, all users will receive their personalized safes with vested tokens.

A vesting period is a time interval during which tokens are unlocked according to a previously approved schedule. The tokens’ unlock logic is programmed into smart contracts and cannot be changed.

A vesting mechanism aims to mitigate pressure on a token market price, reduce the likelihood of speculation, protect the interests of token holders, and positively influence the long-term project development.

Details on vesting periods and the unlock scheme are available in the CrossCurve tokenomics.

The Eywa vesting tokens feature the following:

  1. Limited movement. Allocations above 1.5 million tokens can only transfer their vesting tokens to whitelisted addresses, facilitating an OTC market.

    Allocations of smaller size, including all Airdrops rounds and Community round participants can move their tokens but ONLY by using Eywa NFTs. This feature will be available after the NFT collection migrates to Arbitrum.

    In simple terms, this means that these tokens can be tied to Eywa NFTs and sold on an NFT marketplace at any time before the lock-in period ends.

Migration of Eywa NFTs will be enabled sometime before the TGE. Until then, Eywa NFT tokens can only be purchased on the Tofu marketplace in the Aurora chain.

Once migrated, the collection will be listed on leading marketplaces such as OpenSea and others.

  1. Opportunity to use vesting tokens for staking.

    Eywa vesting token holders can stake their tokens before the end of the vesting period and receive staking/farming rewards.

  2. Opportunity to participate in the CrossCurve DAO to receive veEYWA votes.

Only veEYWA holders will be eligible to receive boosted rewards for liquidity provision, protocols income and bribes.

Simply put, ONLY veEYWA vote holders will be able to receive EYWA tokens as rewards.

Note: Any changes in the accruals during validators’ rounds will be updated here.

Voting

Voting on Emission and Incentive Parameters

Every three months (every 12 epochs), the project may initiate a vote to change the parameters of token emission distribution from the CrossCurve Treasure.

During this voting, the following parameters are determined:

  1. The amount of emission per epoch: the total number of EYWA tokens allocated for the project’s development.

  2. The percentage allocated to pool rewards (Pools incentives).

  3. The percentage allocated to bond creation (Bonds incentives).

  4. The percentage allocated to grants (Grants incentives).

  5. The percentage allocated to attract external rewards to project pools (Bribes incentives).


Voting Conditions and Restrictions

Voting frequency: Once a voting is initiated, the next one can only occur after three months.

Parameters for voting: All five parameters must be proposed for the voting:

  1. Emission amount per epoch.

  2. % for Pool incentives.

  3. % for Bond incentives.

  4. % for Grant incentives.

  5. % for Bribe incentives.

Restrictions:

  • The sum of percentages for parameters 2-5 must total exactly 100%.

  • The emission per epoch cannot exceed the average emission since the DAO’s launch by more than 25%.

  • Reducing emission is not restricted and can be lowered to 0, if DAO participants support it.


Initial DAO Parameters

  • Emission per epoch: 1 262 295 EYWA tokens.

    • 38% — Pool incentives.

    • 25% — Bond incentives.

    • 0% — Grant incentives.

    • 37% — Bribe incentives.


Emission Distribution Algorithm per Epoch

  1. Determining the total emission volume A certain emission amount E is allocated from the EYWA Treasure (for example, the initial 1 262 295 EYWA tokens or another value approved by the DAO).

  2. Calculating staking rewards: The amount of staking rewards S is calculated.

  3. Calculating token volumes for incentives After deducting the staking rewards, the remaining amount is distributed as follows:

Poolsincentives=ratioPools∗(E−S)Pools_{incentives}=ratio_{Pools}∗(E−S)Poolsincentives​=ratioPools​∗(E−S)
Bondsincentives=ratioBonds∗(E−S)Bonds_{incentives}=ratio_{Bonds}∗(E−S)Bondsincentives​=ratioBonds​∗(E−S)
Grantsincentives=ratioGrants∗(E−S)Grants_{incentives}=ratio_{Grants}∗(E−S)Grantsincentives​=ratioGrants​∗(E−S)
Bribesincentives=ratioBribes∗(E−S)Bribes_{incentives}=ratio_{Bribes}∗(E−S)Bribesincentives​=ratioBribes​∗(E−S)

Note:

  • The sum of , ,and coefficients must be 100%.


Voting for Pools

All veEYWA holders can participate in weekly (every epoch) voting to distribute Pool incentives among the pools.

What are Pool incentives?

Pool incentives are EYWA tokens, allocated from the CrossCurve Treasury each epoch to attract liquidity providers to the project. DAO participants vote on how this amount is distributed among the pools.

Benefit for Liquidity Providers

The more votes directed to a pool where a provider’s liquidity is located, the higher their reward in the next epoch.

List of Eligible Pools

Only those pools connected to the CrossCurve project are eligible for Pool incentives distribution:

  1. Pools created by the project before the DAO launch.

  2. Pools added via a DAO vote.

  • Any DAO participant can initiate a vote to add a new pool.

  • To include a pool in the list, the proposal must receive more than 50% of the DAO votes.

Voting Procedure

Voting takes place on a separate page in the DAO section. To participate, a user must:

  1. Distribute all 100% of their votes among the available pools.

  2. Press the "Vote" button to confirm their voting choice.

Before the end of the current epoch, a user can cancel their votes and vote again.


Incentive Distribution Scheme Based on Voting Results

  1. Vote Counting Process:

At the start of a new epoch, all veEYWA votes cast for pools in the previous epoch are counted. The percentages allocated by participants are converted into a specific number of EYWA tokens directed to each pool.

  1. Formula for Incentive Distribution:

EpoolX=VpoolX∑i=1nVpooli∗PoolinsentivesE_{pool X} = \frac{V_{pool X}}{\sum^n_{i=1}V_{pool i}} * Pool_{insentives}EpoolX​=∑i=1n​Vpooli​VpoolX​​∗Poolinsentives​

where:

— the number of EYWA tokens allocated to pool X.

— the total EYWA token amount allocated to all pools in the current epoch

— the amount of veEYWA votes cast for pool X.

— the amount of veEYWA votes cast for pool i out of all n pools

Thus, the number of EYWA tokens allocated to a pool depends on the proportion of veEYWA votes that pool received relative to all votes.


Reward Distribution to Liquidity Providers

At this stage, all incentives allocated each epoch to attract liquidity providers to the project’s pools are distributed via Angle Merkl service.

Funds Flow Scheme:

CrossCurve Treasure → Pools incentives → Gauge → Angle Merkl → Liquidity Providers

Liquidity providers can claim their rewards:

  • Through the project’s pool interface.

  • Through the Angle Merkl service interface.


Boosting Liquidity Provider Income for DAO Participants

If a liquidity provider is also a DAO participant, they receive increased rewards through a boost coefficient B.

Boost Coefficient Formula:

Buser=1.5∗D∗vd∗V+1B_{user} = 1.5 * \frac{D*v}{d*V} + 1Buser​=1.5∗d∗VD∗v​+1

where:

— the user’s boost coefficient (cannot exceed 2.5)

D — the total sum of all deposits in the pool (in USD)

d — the user’s deposit amount in the pool (USD).

V — the total veEYWA of all users.

v — the user’s veEYWA amount.

Calculating the User’s Reward:

A maximum boost of B=2.5 does not mean the reward is simply increased by 2.5 times. The total is divided among all liquidity providers taking into account their individual boost coefficient B.

User Reward Formula:

Rewarduser=Buser∗duser∑i=1nBi∗di∗RewardallReward_{user} = \frac{B_{user}*d_{user}}{\sum^n_{i=1}B_{i}*d_{i}}*Reward_{all}Rewarduser​=∑i=1n​Bi​∗di​Buser​∗duser​​∗Rewardall​

Where:

— the user’s reward

— the total amount of tokens allocated as liquidity rewards

— the user’s boost coefficient

— the user’s deposit size (USD).

— the boost coefficient of user i.

— the deposit size of user i (USD).

Restrictions:

  • Maximum boost coefficient: 2.5.

  • Rewards are distributed proportionally, taking into account each user’s deposit and boost coefficient.

This system incentivizes DAO participants to provide liquidity, increasing their returns thanks to holding veEYWA.

Sonic Incentives on CrossCurve MetaLayer

Introduction

CrossCurve is launching Sonic with an updated pool architecture built on the principle of isolated connections: each network connects to a universal asset within Sonic.

For example, the sxEthereum pool with the universal token xfrxUSD and the s-token с sUSDC_arb

This not only enhances the system's resilience but also opens direct access to all key drop programs of the Sonic ecosystem.

Now, every CrossCurve user can earn three types of rewards just by interacting with the app.

Currently, Sonic incentives are provided for all paired pools on Sonic and for the 3UNIT0 pool.

Season 1

Sonic Points — Rewards for Users

This is the core drop mechanism from Sonic, focused on end users. Points are awarded for holding whitelisted assets and come in two types: passive (for storing assets in a wallet) and active (for using assets in third-party apps, such as CrossCurve), which earn double the passive rate.

Thus, farming Sonic Points through CrossCurve is twice as profitable!

The following assets offer different boosts:

  • scUSD — 6x

  • scETH, scBTC — 4x

At the end of the drop, Sonic Points will be converted into NFT-safes, from which $S tokens will gradually unlock. All information is displayed in the dashboard: my.soniclabs.com/points

For CrossCurve users, this means simply providing liquidity to CrossCurve pools — points are credited automatically, and they will enter the main phase of $S distribution.


Sonic Gems (cmGEMS1) — Rewards for Applications

This is a separate program for protocols and the second part of the Sonic drop. During the first season, 1 680 000 Gems will be distributed. 262 500 have already been pre-allocated to the winners of Sonic Boom. CrossCurve, as one of the winners in the Sapphire tier, has already received 8750 Gems. The remaining 1 417 500 Gems will be distributed based on user activity and multipliers. For CrossCurve as a bridge, a 5x multiplier applies.

We’ve decided to tokenize these as cmGEMS1 and allocate 100% of these tokens as rewards to liquidity providers in the project’s pools.

What is required from CrossCurve users? - Provide liquidity to the project’s isolated Sonic pools on Sonic - Rewards will be distributed through Merkl and will account for your veEYWA boost, if you have one. This can boost your yield up to 2.5x. The instructions to this particular step can be found .

But perhaps the main advantage of cmGEMS1, unlike Points, is that they can be directly exchanged for $S.


Rings Points — Points from Token Issuer on Sonic

Rings Protocol is the issuer of the stablecoins scUSD, scETH and scBTC, which are present in the Sonic pools on CrossCurve. The protocol has its own drop program — Rings Points, which are awarded automatically, similar to Sonic’s own.

Like Gems, Rings Points can be directly exchanged for $S at the end of the season.


Season 2

Sonic Points — Rewards for Users

This is the core drop mechanism from Sonic, focused on end users. Points are awarded for locking whitelisted assets in CrossCurve pools.

The following assets offer different boosts:

  • scUSD — 6x

  • scETH, scBTC — 4x

All information is displayed in the dashboard: my.soniclabs.com/points

For CrossCurve users, this means simply providing liquidity to CrossCurve pools — points are credited automatically, and they will enter the second phase of $S distribution.


Conclusion

CrossCurve’s transition to Sonic is not just an upgrade, but a real expansion of economic opportunities for our liquidity providers. With the new pool architecture, almost every provider can receive triple incentive accrual - not counting CrossCurve’s own rewards.

Sonic incentives apply to all paired pools in the Sonic network, as well as the UNIT0 pool.

CrossCurve MetaPoints Program

As part of Sonic’s Airdrop Season 2, CrossCurve has launched the CrossCurve MetaPoints program to reward active users of CrossCurve.

Rules

Participants:

  • Users who provide liquidity to participating pools* in the Farms tab by staking LP tokens in the CrossCurve app

  • Users swapping cross-chain via the Trade interface (as long the the swap’s route passes through the Hubchain)

Rewards:

Participants receive MetaPoints. Also, their activity helps CrossCurve receive more Sonic Gems, which will be swapped to $S tokens at the end of Sonic’s airdrop season 2. All of the received $S tokens will be distributed among all the participants who got enough MetaPoints to receive at least one $S

Rule subject to change on Sonic’s end as they publish the final algorithm of point accrual

Pool marking:

Pools participating* in the MetaPoints program will be marked with a special symbol .

Point accrual mechanics for liquidity providers

  • Only the specially marked pools in Farms are included

  • Points accrue only for the volume of s-tokens in the LP:

○ E.g., if the LP token only has 40% of its TVL is in s-tokens, then only this 40% counts towards accrual, not the other 60%.

  • Accrual formula:

○ 1 point = 1$ s-token left in the pool for 1 day

  • Accrual frequency:

○ daily at 00:00 UTC

  • Each pool could have an individual multiplier that increases or decreases the total amount of accrued points.

Accrual mechanics for users moving liquidity

  • Only cross-chain swaps receive points (as long as the route passes through the Hubchain).

  • Swaps below $10 do not count.

  • Users get 100 MetaPoints for every $10 swapped

Integration

  • Users can find MetaPoint accrual information on the Leaderboard page in each relevant tab:

- My MetaPoints — total MetaPoints earned by the connected wallet

- In Farms — total MetaPoints earned by staking in Farms

- In Swaps — total MetaPoints earned for cross-chain swaps in Trade

- Total MetaPoints — total amount of MetaPoints earned by all the participants of the CrossCurve MetaPoints program

  • In the “Frams” LP staking interface, participating pools will have the icon next to them, alongside the point multiplier.

  • In the “Trade” interface, the expected point value of the swap will be reflected alongside points from Season 2 of Sonic’s airdrop.


FAQ

1. How do I earn $S tokens Swap on CrossCurve or provide liquidity to CrossCurve pools

2. Which pools are participating in this program? Only the selected pools marked by the program’s icon in the interface

3. Does my entire staking position accrue points? No, only the part reflecting the % of s-tokens in the pool

4. How is the value of the LP token determined? In USD based on the average daily value

5. How frequently do the LP points accrue? Daily

6. What can I do with MetaPoints? At the end of the Sonic’s Airdrop Season 2, they will be converted into $S tokens

Slippage settings

Slippage is the price change caused by external market movements and not related to the user's operation within the pool. Slippage strongly depends on the liquidity volume inside the pool. If a token pool has low liquidity, significant changes in the exchange rate within the pool require less market movement.

In the settings, you can specify slippage (by default, the parameter is set at 0.5%) Slippage is a change in price caused by external market movements and not related to the user's activity in the pool. Slippage highly depends on the liquidity volume inside the pool. If a token pool has low liquidity, significant rate changes within the pool require less market movement.

CrossCurve users can configure the maximum permissible slippage for cross-chain operation:

You can always see the exact total value in Routing details → Total slippage.

When you set a slippage tolerance in the app, this value is treated as the maximum slippage for the entire route.

Allocation rules:

● Stable pools always receive max / 10.

○ Example: if max = 1%, each first stable pool in a chain gets 0.1%.

○ Only the first stable pool in each chain applies slippage.

● Crypto pools receive the remaining slippage.

○ The remainder is evenly distributed across all chains that contain crypto pools.

○ Only the first crypto pool in each chain applies slippage.

● Other swaps in the same chain receive 0%.

● Therefore, total slippage ≤ your chosen max.

Total Slippage is the total effective slippage applied across all networks where a swap occurs during a cross-chain transaction.

It is calculated as the sum of slippage percentages for each individual network involved in the transaction.

Slippage Allocation Examples (Max = 1%)

You can find the rules for distributing slippage in the table below:

Route (per chain)
Allocation (per pool)
Total Slippage

Stable

0.1%

0.1%

Crypto

1%


Note: Only the first pool in each chain receives slippage. Stable pools always = max/10; the rest is evenly split across crypto pools.

Change the slippage parameter only if you clearly understand why you are doing it.

If you set the value too low, you will receive a warning and your transaction may fail due to low slippage:

If you have set a value that is too high (e.g. 1%), which significantly exceeds the recommended value of 0.5%, the transaction may be executed at an unfavorable rate due to frontrun:

Adding liquidity to pools on Sonic

To provide liquidity to Sonic pools:

  • Select the pool where you want to transfer liquidity, e.g., xsArbitrum.

  • Determine the required token amounts.

Easy mode (Imbalanced)

Withdrawing Liquidity

Example of using Easy mode for withdrawing liquidity of the EUSD LP token into the USDT stablecoin

To start working in the CrossCurve application, go to the Liquidity section. After successfully connecting your wallet, in the Choose pool window, select the EUSD pool. This mode allows you to exchange the liquidity token into a single stablecoin without interacting with the liquidity pool interface on Curve.

  1. Having selected the Withdraw operation and Easy mode, proceed to the exchange modal window by pressing Next.

  1. Next, select the USDT stablecoin (or any other available asset participating in the EUSD pool) to withdraw liquidity and choose the preferred network of the received original asset.

  1. After entering the amount of tokens to be withdrawn, the system will calculate the number of LP tokens received and the gas fee. By pressing Routing details, the Routing will be displayed.

  1. The first transaction requires allowing the spending of EUSD by pressing “Approve EUSD” and signing the transaction in the wallet. For signing the transaction, you must hold the native token of the network in which the transaction is being conducted to pay for the gas.

After confirming the spending of EUSD, a “Swap” button will appear.

  1. By pressing the "Swap" button, a request will be sent to the wallet to confirm the transaction of exchanging the EUSD LP token from the EUSD pool to the USDT stablecoin on the Arbitrum network.

6. After signing the transaction, a notification about the transaction sending, the ongoing exchange, and the estimated waiting time will be received. The status and progress will be displayed in the top right corner.

If in Easy mode you see high losses, consider other assets for acquisition or use the Balanced mode of liquidity withdrawal

via Curve (Balanced)

Withdrawing Liquidity

Step 1. Go to xCRVUSDC pool on Curve and analyze the optimal way to withdraw funds from the pool:

A balanced method of withdrawing liquidity from the pool is recommended – you will receive s-tokens in proportion from several assets so that your operation brings the pool into a balanced state.

Step 2. After connecting the wallet, go to the Withdraw/Claim tab and use the Balanced mode. After entering the amount to be withdrawn, the AMM will distribute the s-tokens in proportion to the pool's balance from the total TVL.

This method should be applied to avoid penalties and earn additional profit on Curve in cases when you are working with large sums relative to the total TVL of the pool, or when the pool is close to perfect balance. After pressing Withdraw, confirm the operation in the wallet. After completing the operation, the system will issue a Withdraw Complete message.

Step 3. Convert the required s-tokens in the CrossCurve interface.

On the Pool Details page, there is a link for quick access to the CrossCurve interface to convert s-tokens into original assets.

  1. In the Input window, select the s-token for conversion and specify the amount of s-tokens to be converted.

2. In the Output window, select the token for conversion, approve the spending of the s-token by clicking Approve scrvUSDC_o, and confirm the transaction in the wallet.

  1. After approving the spending of scrvUSDC_o, a Swap button will appear.

4. By pressing the "Swap" button, a request will be sent to the wallet to confirm the transaction of exchanging the scrvUSDC_o s-token for the selected crvUSDC LP.

5. After signing the transaction, a notification about the transaction sending, the ongoing exchange, and the estimated waiting time will be received. The status and progress will be displayed in the top right corner.

Dashboard interface

Description of the Dashboard interface

To get started with the CrossCurve app, visit the Dashboard page. Click Connect wallet, choose your preferred wallet from the list, and confirm the connection, making sure you are on the official page: https://app.crosscurve.fi/dashboard

Upon successfully connecting your wallet, the Dashboard page will display detailed information:

Farms section

  • Farms - shows your liquidity provided in CrossCurve pools and farming rewards earned.

It also presents statistics for pools you've joined:

  • Pool - pool name

  • Staked - quantity of LP tokens you've staked

  • APR - current pool yield

  • Earn - farming rewards earned

To collect your rewards, click Claim and sign the transaction in your wallet, or navigate to the Farms page via the Go to Farms link to manage liquidity and earn rewards on Angle Merkl

Vested section

  • Vested - displays EYWA tokens in vesting safes, locked in DAO, and tokens available for claiming upon vesting completion.

  • Claimable safes section shows the number of safes ready to be claimed and total token amount inside. To claim these vesting safes, click Get your safes and confirm the transaction in your wallet.

  • Vested safes section shows the total number of vesting safes and the token amount contained. Ready to claim displays EYWA tokens with completed vesting periods, available for claiming. To receive these tokens, visit the Claim Portal.

  • Early Farming Program section shows the amount of rEYWA tokens earned from early liquidity provision in CrossCurve pools (more details here). To exchange rEYWA tokens for EYWA, follow the Go to rEYWA link in the Early Farming Program section.

  • Locked in DAO displays your DAO locks, total tokens locked, and the nearest lock expiration date. For a full list of locks in the Locker, click View.

DAO Rewards section

  • DAO Rewards - shows rewards earned from DAO participation.

The Incentives section shows rewards received for your votes on CrossCurve pools. To claim these rewards, click Claim and sign the transaction in your wallet.

NFT section

  • NFT - displays EYWA tokens contained within EYWA NFT containers pending vesting, and the number of EYWA NFTs in the connected wallet.

  • Aurora-NFT-detached EYWA tokens, post-bridging to Arbitrum - displays EYWA tokens detached from EYWA NFTs after bridging from Aurora to Arbitrum (more details here). These EYWA tokens can be claimed as vesting safes by clicking Claim and signing the transaction in your wallet.

  • In wallet - shows the number of EYWA NFTs and the EYWA token amount within NFT containers. Click View to see detailed information.

  • In lock - indicates the number of NFTs in locks. Click View to go to NFT Manager for detailed information.

Vote Interface

Vote Interface Description

Voting for pools and earning incentives

Locking EYWA tokens provides unique opportunities to earn additional income by receiving incentives for voting on specific pools. veEYWA holders use their votes to direct liquidity distribution and rewards across CrossCurve pools. Projects seeking liquidity offer incentives (various tokens) to veEYWA holders in exchange for their votes.

Locking EYWA tokens transforms voting rights into income streams: veEYWA holders select the most beneficial proposals and receive rewards in tokens, cryptocurrencies, or other forms of income from participating projects. The higher your veEYWA balance, the greater your potential rewards.

Using EYWA DAO NFTs further enhances your earnings when voting on pools.

To start using the CrossCurve application, navigate to the Vote page under the DAO section. Click «Connect wallet», select your wallet from the list, and confirm the connection, ensuring you are on the official page: https://app.crosscurve.fi/vote-pools

After successfully connecting your wallet, open the Pools tab to participate in pool voting.

You will see the following details:

  • Current voting round ends in - Countdown timer indicating when the current voting round concludes

  • Total voting power available for this epoch - Combined voting power of all DAO participants for the current epoch

  • You have - Number of your locks and their voting power in veEYWA tokens

  • Voted - Number of your locks and the total veEYWA voting power you have already allocated this epoch

  • Ready for voting - Number of locks available for voting and their total veEYWA voting power

  • Estimated EYWA emission in the next epoch - Estimated EYWA token rewards allocated for the upcoming epoch

  • Estimated CRV emission in the next epoch - Estimated CRV token rewards allocated for the upcoming epoch

  • Estimated incentives available in the current epoch - Estimated incentives from partners allocated in the current epoch (in USD equivalent)

In the window displaying participating voting pools, the following information appears:

  • Pools - Pool name and type (Stable pool**, Volatility pool*)

  • Chain - Network of the pool

  • Incentives - Amount of incentives allocated for votes on each pool during the current epoch

  • vAPR - Projected yield metric for the next epoch, calculated based on current pool votes and TVL

  • Select % vote - Select the percentage of your voting power allocated to the chosen pool

  • Votes sent - Percentage of voting power you have already allocated to each pool

  • Est. rewards - Estimated reward amount in USD equivalent

CrossCurve offers two distinct liquidity pools to users: the Stable Pool and the Volatility Pool:

* Volatility Pools consist of liquidity (Curve pools) for asset pairs with volatile prices, typically experiencing divergence. For example, USDT vs. EYWA or ETH vs. BTC. Volatile pairs are formed by combining uncorrelated assets and utilize Curve's unique impermanent loss compensation mechanism for pools containing volatile assets. ** Stable Pools are pools of stable liquidity (Curve pools) between assets whose prices are pegged to each other. For example, USDT vs. USDC.

Another case involves derivative assets, such as wstETH and rETH. Although rETH is considered a volatile asset, the trading pair between wstETH and rETH is classified as a stable pool because the price of wstETH does not significantly fluctuate relative to rETH.

Stable pairs on CrossCurve are designed for correlated assets and aim to maintain a 1:1 transfer ratio between them as closely as possible.

To participate in voting, select the pool you're interested in, adjust the percentage of your voting power to allocate, and click Vote. Then, sign the transaction in your wallet.

The total of your votes across all pools must equal 100% for the Vote button to become active.

You can view detailed information about your submitted votes by expanding the Votes sent menu.

To cancel your current vote for a specific pool, click Reset. To remove all your votes across all pools, click Reset all.

When confirming vote cancellation, all your votes for the selected pool will be withdrawn. To proceed, click Ok and sign the transaction in your wallet.

Proposals Interface

Proposals provides the CrossCurve DAO community with tools to manage and guide the protocol's development:

- A platform for managing and voting on proposals impacting the CrossCurve protocol

- Decentralized decision-making by token holders

DAO members actively participate in shaping the CrossCurve protocol by:

  • Creating proposals: members can introduce initiatives such as protocol parameter adjustments or fund allocation.

  • Voting: users vote For/Against proposals using their veEYWA tokens (vote weight corresponds to veEYWA balance).

  • Status tracking: displays proposals categorized by active, completed, and pending, along with their outcomes.

To begin interacting with proposals in the CrossCurve app, visit the Proposals page at under DAO → Vote, then click Connect wallet.

The Proposals page lists DAO proposals, each showing:

  • Proposal title and a brief summary

  • Current status:

    • - Pending voting start

- - Link to the proposal author

- - Date of creation

Voting progress is shown in the status bar, displaying:

  • Number of votes For and Against

  • Required quorum in veEYWA tokens

For detailed information, navigate to the specific Proposal page.

To participate in voting, connect your wallet by clicking Connect wallet

  • If the Proposal status is , the required quorum and voting start time will be shown.

  • If the Proposal status is , current voting progress will be displayed Yes or No.

After voting, await voting completion.

  • Once voting concludes, results are shown clearly:

    • - Proposal approved, with a vote weight of 64% Yes

  • - Proposal rejected, with a vote weight of 74% No

  • - Insufficient quorum achieved

Farms Interface

Farms Section and Its Functionality

To start working in the CrossCurve app, go to the Farms page in the Yield section. There, click “Connect wallet” in the top right corner, choose a suitable wallet from the list, and confirm the connection, making sure you are on the original page https://app.crosscurve.fi/farms.

  1. After successfully connecting, you will see all available pools for staking LP tokens in the selected network to earn EYWA or/and CRV.

  • Farm Pool - Pool name

  • Chain - Network where the pool is located

  • TVL - Total volume of funds in the pool

  • Volume - Trading volume in the pool for the past 24 hours

  • Utilization - Liquidity Utilization rate = 24h trading volume / Liquidity

  • Net APY - annual interest rate

  • Earned - number of earned EYWA or/and CRV tokens for the whole staking period

By clicking on the APR Calculator icon, you will see a modal window to calculate your actual vAPR and boost for your deposit based on veEYWA ownership and the resulting EYWA NFT boost. More details you can find here.

By clicking on the vAPR icon you will see detailed information about the rewards in the selected pool.

  • Current vAPR - Current “Variable Annual Percentage Rate”: it is the interest you'd earn on your deposits for a whole year, and it's variable because it depends on today's trading activity in this pool, the price of the assets you deposit, the price of the assets you're rewarded with, and the current rewards rates.

  • Base pool vAPR - “Base pool vAPR” accrues within the CrossCurve pool: this yield does not require claiming; it is automatically accumulated within your LP token.

  • CRV cAPR - “CRV vAPR” is distributed separately and can be claimed on the “Farms” page in the “Farming rewards” section. The amount of this yield depends on your veCRV boost.

  • EYWA DAO vAPR by Merkl - “EYWA DAO vAPR by Merkl” is distributed separately and can be claimed on the “Farms” page in the “Farming rewards” section or directly in . The amount of this yield depends on your veEYWA boost.

  1. By expanding the details window of the selected pool, you can find a link to obtain the LP token via CrossCurve, or through Curve pools and Pool Contract (leads to the pool's LP token contract). You can also find a direct link to Angle Merkl rewards dashboard.

In the Farming rewards window, accrued earnings from farming are displayed.

Staked shows the balance of LP tokens locked for earning EYWA and CRV.

  1. By clicking ‘Stake LP and get rewards’ we will see a modal window of steaking to get EYWA and CRV.

In the field for entering the amount of LP tokens to be deposited, enter the desired amount. By clicking the Get LP link, you can obtain additional tokens on CrossCurve.

  1. The top menu allows sorting the display of pools:

By relevance

By type (Stablecoin, crypto or any pools)

By Popularity, APR, TVL, Liquidity Utilisation and Volume

Claim portal interface

To start using the CrossCurve app, navigate to the Claim portal page in the Vesting section. Click «Connect wallet», select the appropriate wallet from the list, and confirm the connection, ensuring that you are on the official page: https://app.crosscurve.fi/vesting

After successfully connecting your wallet, the app will verify your wallet address against the criteria for eligible EYWA tokens to claim. Please wait for the request to be processed.

If, after the wallet verification request, you see a message stating that the wallet address was not found on the token claim list, please verify the accuracy of the connected wallet address. If you believe an error has occurred, contact support to repeat the verification process:

  • for private round participants, e-mail;

  • for public round participants, e-mail.

After successful verification, you will see all vesting safes available for your wallet address, containing EYWA tokens received in each distribution round. To manage vesting safes, click Get your vesting safes and confirm the transaction in your wallet.

Read more about rounds .

After successfully confirming the transaction, all vesting safes available for the connected wallet will be displayed.

In each type of vesting safe, the following information is displayed:

  • All vested tokens - the number of tokens in the safe that are in vesting

  • Amount to claim - the available amount of tokens to claim

  • Already claimed - the number of tokens already claimed from the vesting safe

  • Time remaining until next claim - the remaining vesting time before tokens can be claimed from the safe

If you have multiple vesting safes for a single round, their number will be displayed in the upper right corner of the safe.

To view detailed information about grouped safes received in one round, hover your cursor over that safe.

Attention! If you see the Claim button inactive - don't worry, it will become active immediately after the listing of EYWA token on CEX. The vesting timer will also start counting from the listing date.

  1. To claim available tokens, select the safe and click Claim, then confirm the transaction in your wallet.

  1. To claim available tokens from grouped safes, click Open to claim.

Choose the safe to claim tokens from, click Claim and confirm the transaction in your wallet.

Early farming program interface

To begin using the CrossCurve application, go to the Early Farming Program page in the Vesting section. Click «Connect wallet», select the appropriate wallet from the list, and confirm the connection, making sure you are on the official page: https://app.crosscurve.fi/reywa-vesting

After successfully connecting your wallet, to display the rEYWA balance in your wallet, you must switch the network to Fantom by clicking Switch chain and confirming the network change in your wallet.

Once connected to the Fantom network, the application will display the rEYWA token balance in your wallet. To exchange rEYWA for the Vesting safe with EYWA, you need to move your rEYWA tokens to the Arbitrum network by clicking Bridge rEYWA to Arbitrum and singing the transaction in your wallet.

To use the bridge and transfer your rEYWA from the Fantom network to Arbitrum, you must have FTM in your Fantom wallet to sign the transaction and pay the gwei in the Fantom network.

After successfully transferring rEYWA from Fantom to Arbitrum, the application will display the balance of the transferred tokens. To start the 90-day vesting period and receive EYWA tokens in exchange for rEYWA, click Start vesting, specify the amount of rEYWA you want to vest, and confirm the transaction in your wallet.

To place your rEYWA in the Arbitrum network into vesting, you must have ETH in your Arbitrum wallet to sign the transaction and pay the gwei in the Arbitrum network.

After placing rEYWA into vesting, the application will display detailed information:

  • Vested - amount of rEYWA tokens that have completed vesting

  • Current vesting - the total amount of rEYWA currently in vesting

In the table, you will see detailed information about ongoing vesting periods:

  • Amount - the amount of rEYWA tokens for each vesting period

  • Date - the vesting end date and the number of remaining days. Complete means completed vesting periods.

  • Penalty - the amount of penalty* in rEYWA tokens for early termination of vesting

* You can find detailed information by following the or by clicking

  1. To receive rEYWA tokens after the vesting period ends, select the vesting safe and click Withdraw, then confirm the transaction in your wallet.

  1. To end the vesting period early and receive rEYWA tokens minus the penalty*, click Exit and confirm the transaction in your wallet.

* The penalty amount is calculated using the following formula:

Vearly=T2912∗VallV_{early}=\frac{T^2}{91^2}∗V_{all}Vearly​=912T2​∗Vall​

Where:

V early - number of rEYWA tokens received on the day T

T - number of vested days passed since the rEYWA claim

V all - total number of rEYWA tokens available on the 91st day, after the vesting period is completed

* You can find detailed information by following the or by clicking

EYWA NFT Gallery

The EYWA NFT collection can be found on the Aurora and Arbitrum blockchains.

You can view your EYWA NFTs right on our website in the NFT->Gallery tab.

The Gallery/Bridge tab allows you to see all the connected wallet’s NFTs on the Aurora chain available for bridging to the Arbitrum chain.

The Gallery/Merge tab allows you to see all of the connected wallet’s NFTs on the Arbitrum chain available for rarity increase via merging.

Gallery / Bridge interface in the Aurora chainGallery / Merge interface in the Arbitrum chain

Gallery / Bridge interface in the Aurora chain

Bridge interface description in the Aurora chain

To interact with the bridge in the CrossCurve app, go to the NFT section and select the «Gallery / Bridge» tab. Click «Connect wallet», select the right wallet from the list, and confirm the connection. Make sure that you’re on the official CrossCurve page:.

After successfully connecting the wallet in the «Bridge» tab, you will see all the available NFTs in your wallet, their level of rarity, and the number of EYWA tokens within the .

In the top right corner, you can toggle between list and icon view options:

Gallery / Merge interface in the Arbitrum chain

Merge interface description in the Arbitrum chain

After successfully connecting your wallet in the «Gallery/Merge» tab, the gallery will show all the NFTs stored in the connected wallet, sorted by rarity.

For your convenience, use the NFT rarity filter to choose the rarity category you want to level up.

Select the necessary number of NFTs for merging and rarity increase and click «Merge»:

Note: The EYWA tokens attached to the NFT were detached from it during bridging. You can see their quantity in the tab.

Then, select a new image for the resulting NFT and click «Accept merge»:

After selecting the new image, you will see information about the NFTs you’re merging and the total number of EYWA contained within them. To merge them, click «Merge» and confirm in the wallet:

After the successful merge, you will get a notification along with a link to the hash of the transaction:

Direct Integration with REST API

CrossCurve MetaLayer API enables cross-chain token swaps across various networks.

Base URL

CrossCurve MetaLayer API is built on REST principles and is served over HTTPS.

https://api.crosscurve.fi

Authentication

Protected endpoints (/routing/*, /pimlico/*, /networks) require an api-key header.

api-key: YOUR_API_KEY

Rate Limits

Tier
Limit

A standard wallet swap (MetaMask, WalletConnect, or any EOA signer) in six steps:

  1. Fetch supported networks and tokens

  2. Find a route

  3. Approve token spending (ERC-20 only)

  4. Send swap transaction

Extract requestId from receipt

  • Poll for completion

  • standard

    60 req/min

    free

    20 req/min

    EOA Swap

    here

    1%

    Stable, Stable (same chain)

    0.1% → 0%

    0.1%

    Stable → Stable (2 chains)

    0.1% → 0.1%

    0.2%

    Stable → Crypto

    0.1% → 0.9%

    1%

    Stable → Stable → Crypto (3 chains)

    0.1% → 0.1% → 0.8%

    1%

    Crypto → Crypto → Crypto (3 chains)

    0.33% → 0.33% → 0.33%

    1%

    Crypto → Crypto → Stable (3 chains)

    0.45% → 0.45% → 0.1%

    1%

    Stable → Crypto (2nd chain)

    0.1% → 0.9%

    1%

    Stable → Crypto → Stable (3 chains)

    0.1% → 0.8% → 0.1%

    1%

    Merkl app
    Dashboard
    here
    - Proposal approved
  • - Proposal rejected

  • - Insufficient quorum

  • - Active voting

  • https://app.crosscurve.fi/proposal
    These parameters can be changed by DAO participants through voting.
    Obtain the synthetic token for this direction, in this case, sUSDC_arb.
  • For USD pools, acquire xfrxUSD tokens. For example, deposit an equal amount of frxUSD and scUSD into the CrossCurve frxUSD pool.

  • Deposit the universal token and the directional (synthetic) token into the paired pool.

  • Let's examine each step:

    To obtain the LP token xfrxUSD, you need to provide liquidity in the CrossCurve frxUSD pool: https://curve.finance/dex/sonic/pools/factory-stable-ng-25/deposit/.

    Go to the CrossCurve frxUSD pool page and connect your wallet.

    Enter the desired deposit amount on the Deposit tab. To avoid losses due to slippage, it’s recommended to deposit funds in a balanced manner by clicking Add all coins in a balanced proportion (learn more here).

    In the first transaction, confirm the spending of funds by clicking Approve Spending and signing the transaction in your wallet.

    In the second transaction, deposit the funds by clicking Deposit and signing the transaction in your wallet.

    After the transaction is successfully confirmed on-chain, your wallet will display the amount of received xfrxUSD LP tokens.

    sUSDC_arb tokens on the Sonic network can be swapped from any available asset in the xsArbitrum pool via the CrossCurve app.

    1. Navigate to the Liquidity tab in the Yield section. Select the Balanced mode and click Next.

    Enter the desired amount to swap, approve the spending by clicking Approve, and sign the transaction in your wallet.

    Click Swap to execute the exchange and confirm the transaction in your wallet.

    1. If you know the swap direction, the exchange can be performed in the Trade tab using Advanced mode with any available asset.

    Navigate to the CrossCurve Stable ARB pool page: https://curve.finance/dex/sonic/pools/factory-stable-ng-73/deposit/ and connect your wallet.

    Enter the desired deposit amount in the Deposit tab. To avoid losses due to slippage, it’s recommended to deposit using the balanced method by clicking Add all coins in a balanced proportion (more details here).

    In the first transaction, approve the spending by clicking Approve Spending and sign the transaction in your wallet.

    In the second transaction, deposit the funds by clicking Deposit and sign the transaction in your wallet.

    After the transaction is confirmed on-chain, the amount of received xsArbitrum LP tokens will appear in your wallet and in the Your Details tab.

    For the Arbitrum example, you need 25% frxUSD and 25% scUSD to obtain 50% xfrxUSD and 50% sUSDC_arb (percentages are based on the total liquidity you plan to transfer to the xsArbitrum pool).

    1. Obtaining xfrxUSD via the Curve App interface

    If your wallet doesn’t support automatic token addition, add it manually as a custom token with the contract address on the Sonic network.

    2. Obtaining sUSDC_arb

    Note: Some directions may experience high slippage!

    3. Adding liquidity to xsArbitrum pool via Curve

    If your wallet doesn’t automatically add the token, manually add it as a custom token using the contract address on the Sonic network.

    To migrate them to the Arbitrum chain, select up to 20 NFTs* and click «Bridge»:

    In the first transaction, confirm migrating the NFTs by clicking «Approve selected NFTs»:

    Then, to migrate them into Arbitrum, click «Bridge» and confirm in the wallet:

    After it’s confirmed on-chain, you will receive a notification about the successful bridging of your NFTs to Arbitrum:

    https://app.crosscurve.fi/nft-bridge
    containers

    * During peak hours, the Aurora network can be unstable: if you can't transfer 20 NFTs, try transferring 10 to 15 NFTs in a single transaction or try again.

    NOTE: After migrating your NFTs to , their copies on will be burned.

    Don’t worry — all your EYWA tokens contained in those NFTs will be detached and merged if bridging multiple NFTs at once. You can always check your balance in the “.”

    After the TGE, tokens will be claimable in the Claim Portal and can again be placed inside an NFT container if you so desire.

    link
    link

    Staking in CrossCurve

    Staking is the simplest way to earn passive income in CrossCurve. All you need to do is lock EYWA tokens (instructions available here), which automatically makes you a member of our DAO and enables you to receive rewards every epoch. You can boost your earnings through additional mechanics like longer lock durations, using NFTs, and participating in votes.

    How does staking work in CrossCurve?

    Each epoch, a portion of EYWA tokens from the DAO Treasury is allocated to incentivize protocol activity. Most of these tokens go to rewarding DAO participants.

    To receive these rewards, you must lock EYWA tokens in the DAO Locker. Once locked, you receive an NFT that records your voting power — veEYWA. The more veEYWA you hold, the larger your share of the rewards.

    Each epoch runs from Thursday 00:00 UTC to Wednesday 24:00 UTC. At the start of each new epoch, rewards from the previous one are distributed.


    Formulas:

    • veEYWA = ((EYWA amount × lock period in weeks) ÷ 156

    • User share = your veEYWA ÷ total veEYWA in DAO

    • Reward = User share × total reward pool (EYWA)

    For example, if you lock 156 EYWA for 1 week, then you will get:

    • 1 veEYWA

    If total veEYWA in the DAO is 1 000, and the reward pool is 1 000 EYWA, then your reward is:

    • 0.1% of the pool = 1 EYWA

    Weekly return rate (WRR): 0.64%

    Your income depends directly on your share of veEYWA. To increase it, you can:

    1. Lock more EYWA tokens

    2. Extend your lock duration

    3. Use EYWA NFT with a

    These methods can be combined. Here are strategy examples:

    Locking 1560 EYWA for 1 week will get you:

    • 10 veEYWA (10 times more)

    If total veEYWA in DAO is 1009, then your share is:

    • 0.99% of the pool = 9.9 EYWA (9.9 times more)

    • Weekly return rate (WRR): 0.63% (almost no change)

    Locking 156 EYWA for 3 years (156 weeks) will get you:

    • 156 veEYWA (156 times more than when locking for 1 week)

    If total veEYWA in DAO is 1 155, and the reward pool equals to 1 000 EYWA, then your share is:

    • 13.5% of the pool = 135 EYWA (135 times more)

    • Weekly return rate (WRR): 86.5% (135 times higher)

    Locking 156 EYWA for 1 week and using NFT with the x3 multiplier will get you:

    • 3 veEYWA (3 times more than without an NFT)

    If total veEYWA in DAO is 1002, and the reward pool equals to 1 000 EYWA, then your share is:

    • 0.29% of the pool = 2.9 EYWA (2.9 times more)

    • Weekly return rate (WRR): 1.9% (approximately 3 times higher)

    Locking 156 EYWA for 156 weeks and applying NFT x3 will get you:

    • 468 veEYWA (468 times more)

    If total veEYWA in DAO is 1467, and the reward pool equals to 1 000 EYWA, then your share is:

    • 31.9% of the pool = 319 EYWA (319 times more)

    Weekly return rate (WRR): 204.5% (319 times higher)

    In addition to the steps you can take to maximize your APR, it’s important to consider “external” conditions. In the section “How to increase staking income,” we looked at examples where the veEYWA volume of other DAO participants was static. But in reality, this figure is constantly changing. One important point: how other participants lock their EYWA also affects your final yield.

    Let’s consider a few simple scenarios with two DAO participants. Suppose that in the previous epoch, only two users participated in the DAO:

    Scenario 1: both locked 75 000 EYWA for the maximum term (3 years)

    • veEYWA of participant A = 75 000

    • veEYWA of participant B = 75 000

    • Total veEYWA = 150 000

    • Shares are equal — both participants receive 50% of the rewards

    Scenario 2: both have 75 000 EYWA, but:

    • Participant A locks for 3 years → 75 000 veEYWA

    • Participant B locks for 1 year → 25 000 veEYWA

    • Total veEYWA = 100 000

    • Participant A receives 75% of all rewards

    Based on the the total reward pool for the week (epoch) is 13 190.73 EYWA, therefore:

    • Reward A: (75 000 / 100 000) × 13 190.73 = 9 892.5 EYWA

    • Reward B: (25 000 / 100 000) × 13 190.73 = 3 297.5 EYWA

    Weekly Return Rate (WRR):

    • WRR A = (9 892.5 ÷ 75 000) × 100% = 13.19%

    • WRR B = (3 297.5 ÷ 75 000) × 100% = 4.37%

    APY calculation:

    • APY A = ((1 + 13.19% ÷ 100%)^52 – 1) × 100% ≈ 62 700%

    • APY B = ((1 + 4.37% ÷ 100%)^52 – 1) × 100% ≈ 824%


    To receive staking rewards each epoch, you must press the “Compound” button. This action adds the accrued reward to the lock amount.

    Increasing the lock amount raises your veEYWA share and, accordingly, your reward in the next epoch. The yield displayed on the locker page (APY) is shown assuming regular use of Compound — based on the principle of bank compound interest.

    If you do not press Compound, your yield will be lower than what is shown in the interface. Therefore, to earn income that matches the displayed APY, you must manually add the reward to the lock each epoch.


    1. Lock EYWA for the maximum term

    2. Use NFTs with a high multiplier

    3. Press “Compound” each epoch

    4. Participate in incentive voting


    Staking in CrossCurve is more than just passive income. It includes many mechanics that allow you to earn returns far beyond traditional staking.

    You’re not just earning — you’re helping shape the CrossCurve ecosystem and receiving real rewards for it.

    Swap interface

    Introducing the CrossCurve User Interface

    By visiting the main page at app.crosscurve.fi, you enter the CrossCurve Application Interface, where you can see three main sections: the Interface for executing token exchange transactions between different networks (Trade tab), the user Dashboard interface for interacting with the DAO, Farming, and NFTs (Dashboard tab), the Airdrop Points statistics page along with referral count (Leaderboard tab), the Interfaces for working with liquidity and yield strategies on CrossCurve (Yield menu), and the menu for interacting with Vesting Safes and rEYWA (Vesting menu). There is also a quick link to the Locker where DAO yields are reflected (Staking APY tab) and a menu for quick purchasing of $EYWA tokens (Buy EYWA menu).

    Swap Section and its Functionality

    To start, in the top right corner click “Connect wallet”, select a suitable wallet from the list and confirm the connection, making sure that you are on the original page app.crosscurve.fi/swap

    After the successful connection, select the desired chain by clicking on your wallet management menu in the top right corner of the page and then on the chain selection pull down in the top left corner of the popup window.

    Select the desired chain from the list or use the search function.

    The interface consist of basic elements, such as:

    If you click on this section pop-up window will appear:

    Here you can change network, fund your connected wallet, see your native token balance in the chosen network, go to transaction history, and disconnect your wallet.

    - copy the connected wallet address and generate a QR code for adding funds:

    - transaction history in the selected network:

    Here you can see the status of your transactions, if your transaction has failed the icon will have red mark .

    Transaction history can be viewed in the log. By clicking on Details, links to the network scanner where the transaction was made will appear, providing detailed on-chain information.

    In the settings, you can specify slippage (by default, the parameter is set at 0.5%) Slippage is a change in price caused by external market movements and not related to the user's activity in the pool. Slippage highly depends on the liquidity volume inside the pool. If a token pool has low liquidity, significant rate changes within the pool require less market movement.

    CrossCurve users can configure the maximum permissible slippage for cross-chain operation (details ):

    Here you can change network and token.

    When you click on source/destination input, then Chains/Token menu opens:

    After clicking on , you’ll see a field to enter the recipient’s wallet address if you want to send to another address.

    Enter the recipient’s address into the Enter address or wallet domain field:

    and click Enter address

    The entered address will be selected as the transaction’s recipient in the Recipient address field.

    In Bookmarked wallets, you can add an address from Recent wallets by clicking on . To delete an address from favorites, click on .

    EYWA NFT Collection

    Unique NFTs from Eywa!

    NFT collection description

    EYWA NFT Characters

    The Eywa NFT collection includes 53 996 unique NFTs. Their number diminishes as they are merged.

    The collection represents four mythical characters: Magician, Dryad, Ant, and Spider. EYWA NFTs are an example of generative art where each character features randomized attributes that grant it uniqueness.

    Eywa NFT Characters

    The characters in the collection are unique creations, drawing inspiration from beloved science fiction universes.

    The Magician Crafted from leaves and various flora types, the magician is inspired by the Star Wars universe and Elemental creatures, as well as ancient Roman and Greek mythology.

    The Dryad This character is inspired by ancient Greek myths, aliens, and the golden era of science fiction, presenting a stunning fusion of a wood nymph with a World of Warcraft (WoW) hero.

    The Ent Assembled from tree bark and roots, the Ent is inspired by the Ents from the Lord of the Rings (LOTR) universe, Swamp Thing from DC Comics, and Groot from Marvel.

    The collection is broken down into five levels of rarity: Common, Uncommon, Rare, Legendary, and Infinity. The rarest of all are the Magician Infinity NFTs, of which there are only 193 in the entire EYWA NFT collection.

    Common

    Currently, the collection is available on the Aurora and Arbitrum networks:

    On the Aurora network, the collection is available for trading within our Telegram communities (Links to Telegram chats for trading Eywa NFTs: ).

    On the Arbitrum network, the collection is available for trading on .

    Here is the Eywa NFT collection address in and .

    The EYWA NFT collection is composed of ERC-721 tokens with the following unique functions:

    • Container function for storing up to 1 500 000 EYWA tokens

    • Merge function that allows you to increase the size of the container and the rarity of the NFT by combining multiple NFTs of one level into one rarer NFT

    • CrossCurve DAO vote multiplier function via veEYWA

    Each NFT in the collection functions as a container for EYWA tokens. You can attach both unlocked and locked in vesting safes* tokens to the NFT. This allows the user to sell blocked EYWA tokens at any time.

    The capacity of each NFT is the maximum number of EYWA tokens it can contain and depends on the rarity of the NFT. The highest capacity — 1 500 000 EYWA — is reserved for the Infinity rarity level NFTs. In the Aurora chain, you can see your current balance of token in the container. Once migrated to the Arbitrum chain, the tokens will be separated from the NFT and can be received as vesting safes via the Claim portal after the TGE.

    For details, see the table below:

    Several NFTs of the same type can be merged to create a single NFT with a higher rarity level. This will also merge all of the tokens contained in the source NFTs.

    Multiplier table for NFT merging:

    Rarity
    Merge multiplicator

    To vote in the CrossCurve DAO, users must lock EYWA tokens — the longer the lock period, the more voting power the user gets. Using EYWA NFTs can also increase voting power. Each NFT can increase the number of available votes by the maximum number of tokens it can contain.

    For details, see the table below:

    Rarity
    Maximum amount of tokens for boost
    Multiplier for veEYWA votes

    After the NFT collection is migrated to the Arbitrum chain, all of the above functions will become available. Before the TGE, we will open up a to move the NFTs from to , as well as the NFT Manager to fully engage with all of the functions of the NFTs.

    The will ensure access to tokens contained in the NFTs, which will be separated from their containers after the migration to Arbitrum and be put together in each user’s wallet. Users will be able to put tokens into vesting safes and keep in the NFTs.

    Working with the EYWA Locker contract in Arbiscan.

    Creating a lock for a vesting safe

    How to find the claimed safe:

    1. Open Arbiscan, and enter the wallet address that received the vesting safe in the search bar, or enter the link in the format https://arbiscan.io/address/{wallet address}, replacing {wallet address} with your wallet address.

    In the list of , filter by the “Claim” function under Method.

    1. In the filtered list, find the claim transaction. To locate the safe addresses, open Transaction Details by clicking on the chosen transaction.

    1. Find the safe address in the Transaction Action or ERC-20 Tokens Transferred, checking the amount of EYWA tokens in that safe.

    1. To copy the safe address, click on it and copy it to your clipboard.

    1. Go to the EYWA Locker contract page: 0xdCa5d16ac3708658ECc971d3AeE5d5CD6e5E1faD , choose and connect your wallet by clicking

    1. Expand the 5t line, createLock, and fill in the fields:

    lockDuration_(unit256) - the lock duration in seconds

    recipient_(address) - the wallet address of the lock’s owner (it’s important that you have access to this wallet)

    vestingWallets_(address[]) - the array of safe addresses*

    1. After the filling in the required fields, click the button and sign the transaction in your wallet.

    Once the transaction is successfully processed on-chain, you will receive an EYWA DAO NFT in your wallet.

    1. Go to your wallet page and expand the TOKEN HOLDINGS list in the Overview tab.

    1. Find the EYWA DAO NFT you received after creating the lock and open its token page.

    1. Find your EYWA DAO NFT ID in the transaction list under the Item column or on the Transaction Details page in the ERC-721 Tokens Transferred section.

    To receive a boost, you must have the EYWA DAO NFT on the same address that you created the lock from, and you must know its ID.

    1. Go to the EYWA NFT contract address 0x33b98A477512A34Af0D311DA5F59FC5341693962 page: and confirm the lock for this NFT in the contract.

    Select and then click

    1. Expand the “approve” first line and fill in the fields:

    to - address of the Locker contract 0xdca5d16ac3708658ecc971d3aee5d5cd6e5e1fad

    tokenid(unit256) - The ID of the NFT to receive the boost. (If you need boosts for multiple NFTs, repeat this operation for each NFT)

    1. Go the the EYWA Locker contract address page 0xdca5d16ac3708658ecc971d3aee5d5cd6e5e1fad

    2. Select then clickand connect your wallet by pressing

    1. Expand the “boost” second line and fill in the fields:

    tokenid_(unit256) - The ID of the lock (EYWA DAO NFT ID), to be boosted.

    collectionTokenIds_(unit256) - the ID(s) of the NFT(s), that will provide the voting boost (If you have only one NFT, enter [id]. For multiple NFTs, [id1, id2], and so on).

    1. After entering the information, click the button and sign the transaction in your wallet. To see your updated voting power, go to the interface.

    Transaction Tracking

    Track the status of a cross-chain swap with GET /transaction/{requestId}.

    Obtaining the requestId

    The requestId is emitted in the ComplexOpProcessed event on the source chain after the transaction is confirmed. You can extract it from the transaction receipt.

    Response structure

    {
      "status": "inProgress",
      "inconsistency": false,
      "source": {
        "chainId": 11155111,
        "transactionHash": "0x...",
        "from": "0x...",
        "events": [],
        "status": "completed"
      },
      "oracle": {
        "relayChainId": 11155111,
        "requestId": "0x...",
        "status": "inProgress",
        "height": null,
        "epoch": null,
        "time": null
      },
      "destination": {
        "chainId": 64165,
        "transactionHash": null,
        "events": [],
        "emergency": false,
        "status": "inProgress",
        "bridgeState": {},
        "error": null
      },
      "data": null
    }

    The response contains three sub-objects representing each phase of the cross-chain operation:

    Sub-object
    Description

    destination.emergency becomes true if over 30 minutes pass without completion.

    Top-level status values

    Status
    Final?
    Description

    Polling recommendations

    • Poll every 10-15 seconds.

    • Set a 15 minute timeout.

    • Stop polling when the top-level status reaches a final state (completed, failed


    Method options

    Execute Options

    const result = await sdk.executeQuote(quote, {
      signer,                    // Required: ChainSigner adapter
      recipient: '0x...',        // Optional: override recipient (default: signer address)
      autoRecover: true,         // Auto-handle recovery on failure
      onStatusChange: (s) => {}, // Status callback during polling
    
      // Gas overrides (optional)
      gasLimit: 500000n,
      gasPrice: 1000000000n,           // Legacy transactions
      maxFeePerGas: 2000000000n,       // EIP-1559
      maxPriorityFeePerGas: 100000000n,
      nonce: 42,
    });

    Tracking Options

    // Track CrossCurve transaction by requestId
    const status = await sdk.trackTransaction(result.requestId);
    
    // Track external bridge by tx hash
    const status = await sdk.trackTransaction(txHash, {
      provider: 'rubic',           // 'rubic' | 'bungee'
      bridgeId: result.bridgeId,   // For Rubic routes
      chainId: 42161,              // Source chain
    });

    Recovery

    CrossCurve routes support three recovery types when transactions fail:

    Type
    Trigger
    Action

    Emergency

    Destination chain emergency state

    Withdraw funds on source chain

    With autoRecover: true, recovery is handled automatically. For manual recovery:

    How to trade

    For your convenience, you can use a single intuitive interface to do all cross-chain swaps and transfers.

    This is thanks to CrossCurve bringing together the optimal available routes from aggregators and bridges to give the user the best value, speed, and efficiency for each transfer.

    Step 1. To access CrossCurve DEX, go to .

    Step 2. Go to the Trade section.

    Step 3. Connect your wallet by clicking the Connect wallet button in the top right corner.

    Early farming program

    Introducing «Early Farming» — a farming program for early liquidity providers!

    For providing liquidity in , the participants will receive rewards in rEYWA tokens. rEYWA — a non-transferable reward token (reward EYWA) that after the listing can be traded for the EYWA token on a 1:1 basis. Participants receive the rewards based on the rules of the Early Farming program, based on the volume of liquidity provided and the pool selected:

    Pool
    Target Pool TVL, $
    rEYWA APR*, %
    Incentives per month, rEYWA
    Monthly yield, %

    Simplified Integration with SDK

    TypeScript SDK for cross-chain token swaps via CrossCurve protocol

    All adapters implement ChainSigner interface with optional getChainId() method.

    CrossCurve SuperDVN

    CrossCurve SuperDVN is a verification module (DVN, Decentralized Verification Network) compatible with the LayerZero . It leverages the CrossCurve Consensus Bridge as its internal mechanism for cross-chain message verification and transmission.

    SuperDVN serves as a sovereign data verification layer for cross-chain applications, providing a decentralized, secure, and resilient environment for communication between blockchains.

    LayerZero uses DVNs to achieve decentralized verification of cross-chain message transfers. However, ensuring robust security requires two or more independent DVNs.

    For developers, SuperDVN appears as a single DVN, but internally it contains a consensus layer composed of multiple messaging protocols, combining their verification capabilities for enhanced reliability and trustlessness.

    DelegationConditionValidatorV1

    DelegationConditionValidatorV1 This is an upgradeable contract that allows you to set additional conditions for delegating locks. It is integrated with EscrowManager, which allows you to know the current status of the lock when delegating it.

    Key Roles and Features:

    1. Access Control: Restricts setAssuranceLockParameters and setMinLockVeEywa calls to the owner of contract(owner()).

    failed

    Yes

    An error occurred

    reverted

    Yes

    Reverted (emergency completion is available)

    retry

    No

    Delivery is being retried

    canceled

    Yes

    Transaction was canceled

    ,
    reverted
    , or
    canceled
    ).

    source

    Status on the originating chain

    oracle

    Validator confirmation status

    destination

    Status on the target chain

    inProgress

    No

    Transaction is being processed

    completed

    Yes

    Successfully completed

    Weekly Return Rate (WRR) = Reward ÷ locked EYWA amount

    APY = 7 906%

    Participant B — 25%

    How to maximize your APR?

    1. Increasing EYWA amount

    Increasing the amount boosts total rewards, but return per token remains almost the same.

    2. Increasing lock duration

    Locking for a longer period significantly boosts both rewards and returns — the most efficient strategy without extra spending.

    3. Using NFT with x3 multiplier

    NFTs give an instant boost — same amount and duration, but 3x higher veEYWA and rewards. This is a great option to multiply your profits.

    4. Combined strategy: increasing lock duration + utilizing NFTs

    Combining max lock duration and NFT multiplier creates a compounding effect, giving a 468x increase in veEYWA compared to the base case. This leads to significant return and relative profit growth.

    Note: All values are illustrative. Actual results depend on total veEYWA distribution across participants. However, the core logic of these calculations remains accurate.

    How other participants affect your APR

    Reward distribution specifics depending on veEYWA amounts

    “Compound” button and APY

    How to maximize earnings

    Conclusion

    veEYWA multiplier
    table
    later
    Arbitrum
    Aurora
    Dashboard

    Retry

    Delivery failed, retry available

    Re-attempt destination delivery

    Inconsistency

    Price deviation detected

    Re-route with new quote

    Error Handling

    npm install crosscurve-sdk
    
    # Plus one signer library:
    npm install viem        # recommended

    Installation

    Quick Start

    Adapters

    Configuration

    Upgradeable via UUPS: Uses UUPSUpgradeable and OwnableUpgradeable patterns, restricting contract upgrades to the owner.

    • UUPSUpgradeable (OpenZeppelin): Provides upgrade functionality under the UUPS proxy pattern, restricted to the contract owner.

    • OwnableUpgradeable (OpenZeppelin): Manages ownership, allowing only the owner to modify critical parameters and authorize upgrades.

    • IDelegationConditionValidatorV1: Defines core methods (e.g., validateDelegations) and events for this contract.

    Additional External References:

    • IDelegationManagerV1: Management of delegated locks

    • IEscrowManagerExtended: Holds locked token data and checks voting power and freeze logic.


    • s_escrowManager (IEscrowManagerExtended) IEscrowManager interface for the EscrowManager contract.

    • s_delegationManager (IDelegationManagerV1) IDelegationManagerV1 for the DelegationManager contract.


    • Description: Disables contract initializers to prevent re-initialization in a UUPS proxy context.


    Description: Configures ownership, references, and initial state:

    • References the escrow manager and delegation manager.

    Parameters:

    • owner_: The address of the contract owner.

    • escrowManager_: The IEscrowManager interface for the EscrowManager contract.

    • delegationManager_: The IDelegationManagerV1 for the DelegationManager contract.


    Description: The function performs checks and determines whether delegation of tokenIds_ from delegator_ to delegatee_ is possible.

    Parameters:

    • delegator_: The address of the contract owner.

    • delegatee_: The IEscrowManager interface for the EscrowManager contract.

    • tokenIds_: The IDelegationManagerV1 for the DelegationManager contract.

    Checks:

    • sender must be a DelegationManager contract. Otherwise, UnauthorizedCaller() is thrown


    • UnauthorizedCaller() Thrown when the caller is not authorized to perform the action.


    DelegationConditionValidatorV1 Being updatable in the long run can provide the opportunity for varied and flexible customization for delegated locks.

    Overview

    Inherited Contracts and Interfaces

    State Variables

    Constructor

    External Functions (Defined by IDelegationConditionValidatorV1)

    initialize(...)

    validateDelegations(address delegator_, address delegatee_, uint256[] calldata tokenIds_)

    Errors

    Summary

    const status = await sdk.trackTransaction(requestId);
    
    if (status.recovery?.available) {
      const result = await sdk.recover(requestId, {
        signer,
        slippage: 1,  // Required for inconsistency recovery
      });
    }
    import {
      // API errors
      ApiError,
      NetworkError,
      ValidationError,
    
      // Transaction errors
      TransactionError,
      InvalidQuoteError,
      InsufficientBalanceError,
      SlippageExceededError,
    
      // Recovery errors
      RecoveryUnavailableError,
      TimeoutError,
    
      // Rate limiting
      CircuitBreakerError,
      RateLimitError,
      ConfigurationError,
    } from 'crosscurve-sdk';
    
    try {
      await sdk.executeQuote(quote, { signer });
    } catch (error) {
      if (error instanceof CircuitBreakerError) {
        console.log(`${error.service} API circuit open, retry after ${error.resetMs}ms`);
      }
    }
    import { CrossCurveSDK, ViemAdapter } from 'crosscurve-sdk';
    import { createWalletClient, createPublicClient, http } from 'viem';
    import { arbitrum } from 'viem/chains';
    import { mnemonicToAccount } from 'viem/accounts';
    
    const account = mnemonicToAccount('your mnemonic');
    const walletClient = createWalletClient({ account, chain: arbitrum, transport: http() });
    const publicClient = createPublicClient({ chain: arbitrum, transport: http() });
    const signer = new ViemAdapter(walletClient, publicClient, account);
    
    const sdk = new CrossCurveSDK();
    await sdk.init();
    
    // Get quote
    const quote = await sdk.getQuote({
      fromChain: 42161,                                      // Arbitrum
      toChain: 10,                                           // Optimism
      fromToken: '0x0000000000000000000000000000000000000000', // Native ETH
      toToken: '0x0000000000000000000000000000000000000000',   // Native ETH
      amount: '1000000000000000',                             // 0.001 ETH (in wei)
      slippage: 0.5,
      sender: account.address,
      providers: ['cross-curve', 'rubic', 'bungee'],  // optional: filter by provider
    });
    
    // Execute with auto-recovery
    const result = await sdk.executeQuote(quote, {
      signer,
      autoRecover: true,
      onStatusChange: (status) => console.log('Status:', status.status),
    });
    
    console.log('TX:', result.transactionHash);
    console.log('Request ID:', result.requestId);
    import { ViemAdapter, EthersV6Adapter, EthersV5Adapter, Web3Adapter } from 'crosscurve-sdk';
    
    // Viem (recommended)
    new ViemAdapter(walletClient, publicClient, account)
    
    // Ethers v6
    new EthersV6Adapter(signer)
    
    // Ethers v5
    new EthersV5Adapter(signer)
    
    // Web3.js v4
    new Web3Adapter(web3, address)
    const sdk = new CrossCurveSDK({
      // API
      apiKey: 'your-key',           // For fee sharing / integrator revenue
      baseUrl: 'https://...',       // Custom API URL
    
      // Validation
      maxSlippage: 5,               // Max slippage threshold (%)
      approvalMode: 'exact',        // 'exact' (recommended) or 'unlimited'
    
      // Polling timing
      polling: {
        initialInterval: 10000,     // 10s initial poll interval
        backoffMultiplier: 1.5,     // Exponential backoff
        maxInterval: 60000,         // 60s max interval
        timeout: 900000,            // 15min timeout
      },
    
      // External bridge polling (Rubic, Bungee)
      bridgePolling: {
        initialInterval: 15000,
        timeout: 1800000,           // 30min timeout
      },
    
      // HTTP client
      http: {
        timeout: 90000,             // Request timeout
        retryMaxTime: 90000,        // Total retry window
        retryInitialDelay: 1000,    // Initial retry delay
        retryBackoffMultiplier: 2,
      },
    
      // Cache
      cache: {
        ttlMs: 600000,              // 10min cache TTL
      },
    
      // Security
      security: {
        allowedHosts: ['custom-api.example.com'],  // Additional allowed hosts
        enforceHttps: true,         // Require HTTPS for non-localhost
      },
    
      // Permit
      permitDeadlineSeconds: 3600,  // 1 hour permit signature validity
    });
    constructor() {
        _disableInitializers();
    }
    function initialize(
        address owner_,
        IEscrowManagerExtended escrowManager_,
        IDelegationManagerV1 delegationManager_
    ) external initializer;
    function validateDelegations(
        address delegator_,
        address delegatee_,
        uint256[] calldata tokenIds_
    ) external view returns(bool);

    infinity

    1 500 000

    rare

    9

    1 legendary

    legendary

    n/a

    n/a

    infinity

    n/a

    n/a

    rare

    25 000

    1.3

    legendary

    250 000

    2.8

    infinity

    1 500 000

    3

    The Spider The spider character embodies an aggressive, dynamic figure, combining an arachnid with a trickster — a mix of Baal from Diablo II, Monsters, Inc., and other characters, infused with elements of insects and alien life forms.

    We have deliberately directed our design team to embrace a “fairytale” aesthetic in the creation of our characters' likenesses. Regardless of age, we all cherish a touch of magic in our lives.

    Echoing the words of Steve Jobs: “Follow your heart, stay hungry, stay foolish!” we are committed to developing the finest cross-chain product on the market. Thank you for your support!

    common

    500

    uncommon

    3 000

    rare

    25 000

    legendary

    250 000

    common

    5

    1 uncommon

    uncommon

    7

    1 rare

    common

    500

    1.006

    uncommon

    3 000

    The utility of EYWA NFTs

    Container

    * Vesting safes are objects containing EYWA tokens that are blocked for a certain period of time based on the rules of the funding round (detailed information about the rules of each round and vesting periods are available here).

    Merge

    veEYWA voting multiplier

    For example, a user with 100,000 EYWA tokens can use one Legendary NFT to give his votes a 2.8 multiplier, since a Legendary NFT type can cover up to 250,000 tokens, or 4 Rare NFTs a 1.3x multiplier each (since each Rare NFT can only cover 25,000). Users can use any number and combination of NFTs for veEYWA vote multipliers to cover all of their holdings of EYWA.

    Migration to Arbitrum

    English speaking region
    CIS region
    OpenSea
    Aurora
    Arbitrum
    bridge
    Aurora
    Arbitrum
    NFT Manager
    rEYWA
    Uncommon
    Rare
    Legendary
    Infinity

    1.036

    Step 4. In the FROM field, specify the token and the chain from which you are sending. This can be done in a special modal window that appears when you click on the chain or token icon.

    Step 5. In the TO field, specify the token and the receiving chain.

    Step 6. Enter the amount you’d like to swap and click to select the full balance of the selected asset. The number of tokens you will receive in the TO field will be calculated automatically.

    Step 7. After entering the total swap amount, the CrossCurve aggregator will show you all the available routes in the Receive field, along with the amount you’re expected to receive, transaction duration, and gas costs.

    Step 8. Select your desired route based on transaction processing time and gas costs.

    When selecting a route, the CrossCurve aggregator gives you small hints about the routes: - the route with the smallest transaction time

    - the route with minimal gas costs

    - the route with the best exchange rate

    Step 9. If the aggregator returns the No routes available result, try to refresh, change the swap amount, select another token pair, or retry this swap at a later time.

    Step 10. To receive the swapped asset to a different wallet, click and enter the destination address in the Enter wallet address field, then select your desired route in the Receive field.

    Step 11. Give the CrossCurve application Approve or Permit permission for the CrossCurve smart contracts to interact with the assets you are sending, as specified in the FROM field.

    Step 12. Click the Swap button to execute the cross-chain operation.

    Step 13. Sign the transaction in the wallet connected to the app.crosscurve.fi application.

    After submitting a cross-chain transaction, you can track the progress of the cross-chain operation in the Transaction history:

    Each cross-chain operation consists of multiple stages. In the Transaction history section, users can track the status of its execution and review its component transactions.

    If a cross-chain operation was interrupted for any reason, you will see an appropriate notification in the Transaction history. The interface will provide options for further actions.

    A modal window is used for selecting chains and tokens:

    In the Select chain menu on the right, select the desired chain. On the left side, you will see all of the tokens available to send / to receive on that chain.

    You can use the search function to find a chain or token by its smart contract address.

    If you select All Chains, search will sort the tokens available in your wallet to appear at the top of search results based on the balance amount. Below them, you will see the tokens supported by the CrossCurve aggregator in alphabetical order.

    The icon indicates to which chain the wallet is currently connected. To add the network into your favorites and have it displayed at the top of the list, click . Favorited chains will be marked as .

    For your convenience, you can Search by name of the token’s ticker or by its smart-contract address.

    You can also search for your desired chain.

    Hovering over any token will show a quick link for adding that token to your wallet and a link to that token’s smart-contract address on the scanner.

    https://app.crosscurve.fi/

    If the transaction has a high price impact, an additional window will appear before signing the transaction, where you will need to confirm the operation. This is to prevent accidental loss of user funds.

    For more detailed information, you can refer to the section.

    Modal window for selecting chains and tokens

    xSTABLE

    $10 000 000

    50%

    2 978 к

    4,16%

    xWETH

    $10 000 000

    25%

    1 489 к

    2,08%

    xBTC

    These pools allow the participants to receive earnings (Net APY) that combines the base rEYWA earnings per the above table + vAPY in Curve pools.

    rEYWA tokens have a 90-day vesting period starting from the claim, which can be done at any time. Once the vesting period is over, rEYWA can be converted to regular EYWA tokens 1:1. Exchanging rEYWA to EYWA is possible only after the listing.

    If a participant wishes to do this exchange prior to the completion of the vesting period, he will be able to convert only those rEYWA that have vested based on the vesting schedule. The rest of his rEYWA will be returned to the CrossCurve DAO’s treasury.

    The formula for exchanging rEYWA for EYWA before the 90-day vesting period ends is as follows:

    Where:

    V early - number of rEYWA tokens received on the day T

    T - number of vested days passed since the rEYWA claim

    V all - total number of rEYWA tokens available on the 91st day, after the vesting period is completed

    Participants can choose to wait until the vesting period is over or take part of their tokens earlier based on their needs and strategy.

    Where:

    T = 21 (vesting days since the claim),

    V all = 10,000 rEYWA (total number of rEYWA tokens that could be claimed on day 91).

    Therefore, on day 21, the participant would only receive 500 rEYWA out of 10,000. These are the tokens he would be able to exchange for EYWA after the listing. The remaining 9,500 tokens would be returned to the DAO's treasury.

    How it works

    Available pools and their earning potential:

    CrossCurve pools
    Vearly=T2912∗VallV_{early}=\frac{T^2}{91^2}∗V_{all}Vearly​=912T2​∗Vall​
    Vearly=T2912∗VallV_{early}=\frac{T^2}{91^2}∗V_{all}Vearly​=912T2​∗Vall​
    Vearly=212912∗10000=500V_{early}=\frac{21^2}{91^2}∗10000=500Vearly​=912212​∗10000=500

    Base income calculations include the assigned incentives for the 3 pools and the TVL in each pool.

    *The rEYWA APR is calculated at the EYWA price of $0.14. You can use this calculator to simulate your earnings with different EYWA prices:

    rEYWA claim and vesting schedule

    An example with 10 000 rEYWA converted on Day 21 after the claim:

    • The OApp application sends a message on the source network to the LayerZero Endpoint contract.

    • The LayerZero protocol processes the message in its standard way and forwards it for verification to the CrossCurve DVN contract.

    • The CrossCurve DVN prepares and sends the verification data to the CrossCurve Gatekeeper.

    • The Gatekeeper dispatches this data through multiple messaging protocols.

    • Each protocol, following its standard cross-chain messaging procedure, independently delivers the data to the CrossCurve Receiver contract.

    • The Receiver collects the incoming message instances and emits events upon receipt.

    • The external service CrossCurve Pusher monitors these events. Once the original message and a sufficient number of verification confirmations are detected, it submits an execution transaction to the CrossCurve Receiver contract.

    • Upon receiving the transaction from CrossCurve Pusher, the Receiver checks that the original message and all required protocol confirmations are present.

    • If verification succeeds, the data is passed back to the CrossCurve DVN, which forwards the verification data to the ReceiveLib contract to complete the verification process and allow LayerZero to proceed with message delivery.

    SuperDVN is fully compliant with the LayerZero DVN Standard, which provides:

    Ability to connect as a primary DVN for cross-chain messaging between networks using LayerZero.

    Support for custom DVN, allowing SuperDVN to be used for specific applications.

    Compatibility with the LayerZero ecosystem without the need to modify smart contracts.

    SuperDVN leverages CrossCurve Consensus Bridge to enhance verification security.

    Currently, the Consensus Bridge supports the following messaging protocols:

    • CrossCurve Oracle Network

    • LayerZero

    • Axelar

    • Router Protocol

    To integrate SuperDVN into an OApp, you need to configure the ULN as specified in the LayerZero documentation.

    Here is an example configuration for using a single SuperDVN:

    SuperDVN.address — the address of the SuperDVN contract on the OApp network that sends the message.

    To configure the OApp, use the following contract addresses:

    Network
    CrossCurve SuperDVN Address

    Ethereum Sepolia Testnet

    Arbitrum Sepolia Testnet

    Overview

    Architecture

    DVN standard
    const ulnConfig = {
        confirmations: 1,
        requiredDVNCount: 1,
        optionalDVNCount: 0,
        optionalDVNThreshold: 0,
        requiredDVNs: [SuperDVN.address],
        optionalDVNs: []
      };
    
    
      const encodedUlnConfig = ethers.utils.defaultAbiCoder.encode(
        ["tuple(uint64 confirmations, uint8 requiredDVNCount, uint8 optionalDVNCount, uint8 optionalDVNThreshold, address[] requiredDVNs, address[] optionalDVNs)"],
        [ulnConfig]
      );

    Message Flow:

    Integration with LayerZero

    Supported Protocols

    Connection and Integration

    Contracts

    Basic interface elements

    1. Wallet management menu

    After completing all your wallet-related activity in our interface, we recommend disconnecting the wallet by clicking on

    2. Transaction History

    Maximum transaction time: 30 minutes. If the maximum time is exceeded, please contact our support team in our official Telegram / Discord channel

    3. Slippage settings.

    4. Source and destination input.

    5. Send to wallet

    here

    Make sure you remember the address(es) of the safe(s) that you plan to deposit into the Locker.

    How to create a lock for a safe whose address you already know

    * for locking a single safe, enter the safe address [address] in the square brackets in the field vestingWallets_(address[]). For two safes, [address1, address2], and so on.

    To later boost your votes, remember the ID (EYWA DAO NFT ID) of the created lock.

    Boosting votes by adding an NFT.

    Voting boost

    https://arbiscan.io/address/0xdca5d16ac3708658ecc971d3aee5d5cd6e5e1fad#writeContract
    https://arbiscan.io/address/0x33b98A477512A34Af0D311DA5F59FC5341693962
    https://arbiscan.io/address/0xdca5d16ac3708658ecc971d3aee5d5cd6e5e1fad#writeContract
    Locker
    0xf1232a1ab5661abdd6e02c6d8ac9940a23bb0b84
    0x440bcab62d629ba60ca56b80e565636e0c404e60

    EYWA NFT Manager interface

    EYWA NFT Manager interface description

    In the EYWA NFT Manager, users can see information about the number of EYWA tokens in each NFT container and vesting periods simply by entering the ID of any NFT in the collection. After connecting their wallet, users can also manage their vesting safes* and add EYWA tokens to NFT containers**.

    * Vesting safes are objects containing EYWA tokens that are blocked for a certain period of time based on the rules of the funding round (detailed information about the rules of each round and vesting periods are available ).

    ** Container - each NFT in the collection functions as a container for EYWA tokens. You can attach both unlocked and locked in vesting safes tokens to the NFT. This allows the user to sell blocked EYWA tokens at any time.

    To find an NFT’s container and vesting information using its ID, one should go into the «EYWA NFT Manager» section, connect his wallet, and enter the number into the «NFT ID» field:

    Search for NFT ID

    To find the NFT ID, go to the OpenSea collection page for EYWA NFTs, making sure that the address matches the original address of the collection: https://opensea.io/collection/eywa-nft-4

    Choose an NFT of interest and go to its page.

    You will see the NFT ID in the name of the selected NFT.

    To quickly get into the app, use the View website link in the More menu.

    After entering the NFT ID into the search bar, the EYWA NFT Manager will show you information about the found NFT:

    On the EYWA NFT Manager page, you can use the “search via NFT ID” function or choose one of your NFTs from the My NFTs gallery.

    After selecting the NFT, the search window will show detailed information:

    • NFT rarity and remaining space in the container

    • Total number of tokens in the safe

    • Rounds in which the EYWA tokens were received and their vesting period: total number of received tokens in each round, number of unlocked tokens, and when the vesting of the locked tokens ends

    Detailed information about rounds and visiting periods can be found.

    To manage your NFTs in the CrossCurve app, you need to go to the Manager page in the NFT section. In the top right corner, click on «Connect wallet», select the right wallet from the list, and confirm the connection, making sure that you are on the official page:

    After successfully connecting the wallet, in the «Total in wallet» tab you will see your total EYWA token balance (wallet Balance plus vesting safes) as well as information about rounds where these tokens were received and their vesting period:

    • Total number of tokens received in the round

    • Number of unlocked tokens

    • End of vesting period for locked tokens

    In the My NFTs section, you’ll see all the EYWA NFTs from the connected wallet with detailed information about each one:

    • ID

    • Rarity

    • Number of EYWA tokens in the NFT container

    • To remove tokens from the NFT container, enter the number of tokens and click «Detach from NFT». Then confirm in your wallet:

    After the on-chain confirmation of the transaction, you will receive a notification that the NFT safe was successfully updated:

    • To attach tokens to an NFT safe, enter the number of EYWA tokens, select the vesting safes that contain those tokens, and click «Attach to NFT». Then confirm in your wallet:

    When adding tokens to NFTs, safes of the same type and vesting period are merged.

    After the on-chain confirmation of the transaction, you will receive a notification that the NFT safe was successfully updated:

    Adding liquidity to pools on Taiko

    To provide liquidity in the or pool on the Taiko network, you need to obtain or LP tokens. These LP tokens consist of two assets: the stablecoin and the synthetic derivative, or and , respectively.

    Since the CrossCurve Stable and CrossCurve WETH pools have migrated from the Sonic network to the Taiko network, you need to acquire the assets on the new network in order to receive the LP tokens.

    If you hold LP tokens on the Sonic network, you need to go to the pool page: and perform a Withdraw of the LP tokens, receiving and for the pool.

    0xA8e6c5932fc3F0BBd4532e911BC1e14db78F35e9
    0x2245F56774fa53966643bCeC94F916cBd16AA854

    $10 000 000

    25%

    1 489 к

    2,08%

    Operation Interruption

    The xfrxUSD and s2Pool_t tokens from the xsTaiko pool on the Sonic network can be exchanged for USDC and sxfrxUSD_s on the Taiko network, respectively:

    Go to the Liquidity tab in the Yield section on the xsTaiko pool page: https://app.crosscurve.fi/liquidity?pool=0xedcf9ef9b389a8f52e81958d8212faf6fbd758ae&type=curve&action=withdraw&input=0x54f0055f387e7dcbfa060eaed81ea8bf1f6c808f&output=0x07d83526730c7438048d55a4fc0b850e2aab6f0b&chainIn=146&chainOut=167000

    Select the Withdraw action in Balanced mode and click Next.

    Enter the amount of s2Pool_t tokens and perform the Swap to USDC.

    Go to the Liquidity tab in the Yield section on the xsoTaiko pool page: https://app.crosscurve.fi/liquidity?pool=0xa17aa5ee656849221c8d9d062894e1145cbda864&type=curve&action=deposit&input=0xf1232a1ab5661abdd6e02c6d8ac9940a23bb0b84&output=0xb1712abdaf3f2959c0d5063e827ddb8183145f11&chainIn=146&chainOut=167000

    Select the Deposit action in Balanced mode and click Next.

    Enter the amount of xfrxUSD tokens and perform the Swap to sxfrxUSD_s.

    If you hold xeTaiko LP tokens on the Sonic network, you need to go to the pool page: https://www.curve.finance/dex/sonic/pools/factory-stable-ng-99/withdraw/ and perform a Withdraw of the LP tokens to receive xfrxETH and sWETH_t for the CrossCurve WETH TAI pool.

    xfrxETH and sWETH_t tokens from the xeTaiko pool on the Sonic network can be exchanged for sxfrxETH_s and WETH on the Taiko network respectively: Go to the Liquidity tab in the Yield section on the xeTaiko pool page: https://app.crosscurve.fi/liquidity?pool=0x6d9f0ff2b7f1397ee731f6370d8e4699ffad7bc5&type=curve&action=withdraw&input=0x8af98914c95a3ec6e790d79e9ef9072e307fc086&output=0xa51894664a773981c6c112c43ce576f315d5b1b6&chainIn=146&chainOut=167000 Select the Withdraw action in Balanced mode and click Next.

    Enter the amount of sWETH_t tokens and perform the swap to WETH.

    Go to the Liquidity tab in the Yield section on the xeoTaiko pool page: https://app.crosscurve.fi/liquidity?pool=0xe16ab7fb5d2c7c1b69f7ce58d390b78ab59e44ae&type=curve&action=deposit&input=0x346704605c72d9f5f9f02d651e5a3dcce6964f3d&output=0xa494f19b34f6aa77ce6d968c752b6321d7b069b3&chainIn=146&chainOut=167000 Select the Deposit action in Balanced mode and click Next.

    Enter the amount of xfrxETH tokens and perform the swap to sxfrxETH_s.

    sxfrxUSD_s tokens on the Taiko network can be obtained by exchanging them for assets available in the xsoTaiko pool in the CrossCurve application.

    1. Go to the Liquidity tab in the Yield section. Select the Deposit action in Balanced mode, then click Next.

    Choose the desired asset and enter the amount you want to exchange, then confirm the spend by clicking Approve, and sign the transaction in your wallet.

    Click Swap to exchange and confirm the transaction in your wallet.

    2. If you know the exchange direction, you can perform the swap in the Trade tab for any available asset using the Advanced mode .

    sxfrxETH_s tokens on the Taiko network can be swapped into from any available asset in the xeoTaiko pool in the CrossCurve application.

    1. Go to the Liquidity tab in the Yield section. Select the Deposit action in Balanced mode, then click Next.

    Choose the desired asset and enter the amount you want to exchange, then confirm the spend by clicking Approve, and sign the transaction in your wallet.

    Click Swap to exchange and confirm the transaction in your wallet.

    1. If you know the exchange direction, you can perform the swap in the Trade tab for any available asset using the Advanced mode .

    Go to the CrossCurve Stable pool page https://www.curve.finance/dex/taiko/pools/factory-stable-ng-5/deposit/ and connect your wallet.

    Enter the desired deposit amount in the Deposit tab. To avoid losses due to slippage, it is recommended to deposit funds using the balanced method by clicking Add all coins in a balanced proportion (more details here).

    With the first transaction, confirm the spend by clicking Approve Spending and signing the transaction in your wallet.

    With the second transaction, deposit the funds by clicking Deposit and signing the transaction in your wallet.

    After successfully confirming the transaction on-chain, the amount of received xsoTaiko LP tokens will be reflected in your wallet and in the Your Details tab.

    You must hold ETH on the Taiko network in your wallet to pay the gas fees.

    Swapping assets from Sonic to Taiko

    If you previously participated in the CrossCurve Stable TAI or CrossCurve WETH TAI pools on the Sonic network, you need to perform a number of steps to obtain the new assets on the Taiko network:

    xsTaiko → xsoTaiko

    We recommend performing the Withdraw in Balanced mode to reduce loss risk due to slippage.

    CrossCurve Stable
    CrossCurve WETH
    xsoTaiko
    xeoTaiko
    USDC
    sxfrxUSD_s
    WETH
    sxfrxETH_s
    xsTaiko
    https://www.curve.finance/dex/sonic/pools/factory-stable-ng-78/withdraw/
    xfrxUSD
    s2Pool_t
    CrossCurve Stable TAI

    xeTaiko → xeoTaiko

    We recommend using the Balanced mode when withdrawing to minimize losses due to slippage.

    Obtaining sxfrxUSD_s

    Note: in some directions, high slippage may occur!

    Obtaining sxfrxETH_s

    Attention: in some directions, high slippage may occur!

    Adding liquidity to xsoTaiko pool via Curve

    If your wallet does not support automatic token addition, add it manually as a custom token using the contract address on the Taiko network.

    EYWA NFT Manager interface description

    Attention! If you buy NFT with EYWA tokens in a container, we recommend using the Buy now function to avoid detaching EYWA tokens before confirming the purchase. If you are buying on an Auction by sending your Offer or on an OTC marketplace - there is a possibility of falling for an unscrupulous seller who may detach the tokens from the container before sending the NFT to the buyer. The Buy now instant purchase feature on OpenSea significantly reduces this risk.

    Removing tokens from the NFT container

    Attaching tokens to the NFT safe

    Keep in mind the maximum capacity of each NFT (based on rarity). If all of the tokens do not fit into the NFT, you will need to use additional NFTs or decrease the number of tokens in the safe after they are vested.

    EYWA NFT Manager
    here
    https://app.crosscurve.fi/nft-manager
    here

    GaugeFactoryV1

    Overview

    GaugeFactoryV1 is an upgradeable factory contract responsible for deploying and initializing Gauge contracts within the CrossCurve ecosystem. These gauges are used to manage and distribute rewards for various liquidity pools or other vote-driven incentives. The factory integrates with an Escrow Vote Manager to ensure that only the authorized vote manager can create new gauges, thus maintaining a secure and controlled environment for gauge deployments.

    Key Roles and Features:

    1. Gauge Deployment: Deploys a new GaugeV1 instance as an upgradeable proxy (using ERC1967Proxy), specifying an implementation, an owner, and initial parameters for reward distribution campaigns.

    2. Access Control: Restricts createGauge calls to the escrow vote manager (s_escrowVoteManager).

    3. Upgradeable via UUPS: Uses UUPSUpgradeable and OwnableUpgradeable patterns, restricting contract upgrades to the owner.

    By implementing IGaugeFactoryV1, GaugeFactoryV1 provides a standardized interface and event structure for gauge creation, enabling other contracts in the CrossCurve ecosystem to request new gauges securely.


    • UUPSUpgradeable (OpenZeppelin): Provides upgrade functionality using the UUPS proxy pattern. Only the owner can authorize upgrades.

    • OwnableUpgradeable (OpenZeppelin): Establishes ownership and restricts certain critical functions (like upgrades) to the contract owner.

    • IGaugeFactoryV1: Declares functions (initialize and createGauge

    Additional External References:

    • ERC1967Proxy (OpenZeppelin): A proxy implementation that stores the logic contract address in storage per EIP-1967.

    • IDistributionCreator.CampaignParameters: Used to initialize reward distribution parameters for newly created gauges.

    • GaugeV1: The gauge implementation contract being deployed as a proxy.


    • s_escrowVoteManager (address): The address of the escrow vote manager contract authorized to create new gauges. Only s_escrowVoteManager can call the createGauge function.


    • Description: Disables initializers to prevent re-initialization in a UUPS upgradeable setup. Ensures the initialize function can only be called once.


    • Description: Initializes the factory contract by setting the contract owner (owner_) and the escrow vote manager (escrowVoteManager_). This function can only be called once due to the initializer modifier.

    • Parameters:


    • Description: Deploys and initializes a new GaugeV1 contract as an ERC1967Proxy, passing in the gauge implementation address, initialization arguments, and returning the newly created gauge address.

    • Parameters:

      • owner_: The address that will become the owner of the new gauge contract.


    • Description: Restricts the contract’s upgrade function (in a UUPS proxy context) to the owner, ensuring unauthorized parties cannot upgrade the factory logic.


    • Emitted When: A new gauge contract is deployed via createGauge.

    • Parameters:

      • gauge: The address of the newly created gauge (proxy).


    • Description: Thrown if createGauge is called by an address other than s_escrowVoteManager. Ensures gauge creation is limited to the authorized escrow vote manager.


    GaugeFactoryV1 securely and upgradeably deploys GaugeV1 contracts under the control of the escrow vote manager. By enforcing that only the designated manager can call createGauge, it prevents unauthorized deployments while still allowing flexible, time-extended reward distribution campaigns. The combination of UUPS upgradeability, ownership checks, and a standardized creation event (GaugeCreated) supports a robust, maintainable environment for launching new gauges in the CrossCurve ecosystem.

    CalldataHelperV1

    Overview

    CalldataHelperV1 is an upgradeable contract that assists with decoding and slicing transaction calldata. It extracts critical parameters such as method-specific calldata, a target address, and a chain identifier from a given input. This functionality is useful in scenarios where cross-chain calls or proxy calls need to parse custom-encoded calldata.

    By implementing ICalldataHelperV1, the CalldataHelperV1 contract ensures a standardized interface for:

    • Initializing ownership through an upgradeable pattern.

    • Decoding calldata to separate out function-specific parameters from overhead bytes (e.g., selectors).

    • Validating slicing operations to prevent out-of-bounds data reads.


    • UUPSUpgradeable (OpenZeppelin): Provides functions for upgrading this contract in a UUPS proxy setup, ensuring only the owner can authorize upgrades.

    • OwnableUpgradeable (OpenZeppelin): Implements ownership-related logic, allowing only the contract owner to perform certain actions.

    • ICalldataHelperV1: Declares the initialize and decode


    This contract does not introduce new constants besides those inherited or implied from the interface. It also does not maintain any additional state variables beyond upgradeability and ownership structures provided by OpenZeppelin libraries.


    • Description:

      • Disables initializers to ensure this upgradeable contract cannot be re-initialized after deployment, following best practices for UUPS proxy pattern.


    • Description:

      • Initializes the contract in an upgradeable context.

      • Sets up ownership by transferring ownership to the specified owner_.


    • Description:

      • Decodes the provided calldata to extract three main elements:

        1. m_calldata: The method-specific or function-specific bytes of calldata.


    • Description:

      • Restricts contract upgrades so that only the owner may authorize them, protecting upgrade logic from unauthorized calls.


    • Description:

      • Extracts a slice from data_ starting at offset start_ for length_ bytes.


    • Description: Indicates that the requested slice exceeds the bounds of the original array (start_ + length_ > data_.length).


    CalldataHelperV1 provides a lightweight, upgradeable solution for parsing transaction calldata and extracting specific parameters like function-specific calldata, target addresses, and chain IDs. It integrates with standard libraries for safe upgradeability (UUPSUpgradeable) and ownership control (OwnableUpgradeable), ensuring secure and maintainable deployment. By strictly enforcing slice parameter checks and skipping the initial 4 bytes, CalldataHelperV1 simplifies the process of handling custom-encoded transaction data in cross-chain or proxied contexts.

    EYWA NFT

    The Eywa NFT collection includes 53 996 unique NFTs. Their number diminishes as they are merged.

    The collection represents four mythical characters: Magician, Dryad, Ant, and Spider. EYWA NFTs are an example of generative art where each character features randomized attributes that grant it uniqueness.

    The collection is broken down into five levels of rarity: Common, Uncommon, Rare, Legendary, and Infinity. The rarest of all are the Magician Infinity NFTs, of which there are only 193 in the entire EYWA NFT collection.

    CrossCurve Consensus Bridge

    CrossCurve Consensus Bridge (CCB) is a cross-chain communication protocol that enables reliable data and asset transfers between networks without relying on centralized intermediaries.

    The system is built on a consensus mechanism among independent cross-chain messaging services, ensuring the authenticity of cross-chain messages received on the destination network.

    The goal of CCB is to provide developers with a secure way to connect their dApps, DeFi protocols, DAOs, and Infrastructure Services to a multi-network ecosystem using a standardized API and a minimal set of dependencies.

    The fundamental model of cross-chain interaction has been used in various forms for quite some time.

    In

    GaugeV1

    GaugeV1 is an upgradeable contract used to manage reward distributions for a particular pool or strategy in the CrossCurve ecosystem. The contract primarily integrates with the Escrow Vote Manager (s_escrowVoteManager) to authorize reward notifications and uses a Distribution Creator (DISTRIBUTION_CREATOR) for executing reward distribution campaigns.

    Key features include:

    • Upgradeable (UUPS Pattern): The contract can be updated while preserving state.

    Routing Response

    POST /routing/scan/stream streams route objects as NDJSON (newline-delimited JSON). Each line is a JSON object with either a simulation field (success) or an error field (failure). The simulation object contains the fields below.

    POST /routing/scan returns all routes as a single JSON array. Each item has the same fields. Use /routing/scan/stream for better responsiveness — routes arrive as they are evaluated, rather than waiting for all providers to finish.

    ) and the
    GaugeCreated
    event. Also defines the
    InvalidCaller
    error.
    owner_: The address designated as the owner of this factory.
  • escrowVoteManager_: The address of the authorized escrow vote manager contract.

  • Effects:

    • Calls __UUPSUpgradeable_init() to set up the UUPS upgrade mechanism.

    • Calls __Ownable_init(owner_), assigning ownership to owner_.

    • Sets s_escrowVoteManager to escrowVoteManager_.

  • eywa_: The address of the EYWA token the gauge will handle for reward distribution.

  • campaignParameters_: A struct of parameters (e.g., schedule, amounts) used by the gauge for reward distribution.

  • Checks:

    • The caller must be s_escrowVoteManager. Otherwise, InvalidCaller() is thrown.

  • Logic:

    1. Deploys a new GaugeV1 implementation contract.

    2. Instantiates an ERC1967Proxy pointing to that implementation.

    3. Encodes the constructor arguments (owner, escrow vote manager address, EYWA token address, campaign parameters) for the gauge’s initialize function call via the proxy.

    4. Emits the GaugeCreated event with the new gauge’s proxy address and the gauge implementation address.

  • Return:

    • address: The newly deployed gauge proxy contract.

  • Events:

    • GaugeCreated(m_gauge, m_implementation): Indicates a new gauge contract was created.

  • implementation: The address of the gauge implementation contract used for the new proxy.

    Inherited Contracts and Interfaces

    State Variables

    Constructor

    External Functions

    initialize(...)

    createGauge(...)

    Internal Functions

    _authorizeUpgrade(address)

    Events

    GaugeCreated(address indexed gauge, address indexed implementation)

    Errors

    InvalidCaller()

    Summary

    functions, as well as the
    InvalidSliceParameters
    error.

    Can only be called once due to the initializer modifier from OpenZeppelin.

  • Parameters:

    • owner_: The address of the contract owner.

  • Effects:

    • Calls __UUPSUpgradeable_init() and __Ownable_init(owner_), configuring the contract for UUPS upgradeability and ownership management.

  • m_target: The address the calldata is meant to target.

  • m_chainId: The chain identifier for cross-chain or multi-chain scenarios.

  • Skips the first 4 bytes, typically used as a selector or prefix.

  • Parameters:

    • calldata_: The full calldata to decode, where the first 4 bytes are not part of the relevant data for extraction.

  • Return:

    • m_calldata: The extracted method calldata (bytes).

    • m_target: The extracted target address (address).

    • m_chainId: The extracted chain identifier (uint64).

  • Logic:

    • Calls the private _slice function to remove the first 4 bytes.

    • Uses abi.decode(...) with a tuple (bytes, address, uint64, address) to decode the relevant fields (although the last address is ignored in this particular decode pattern).

  • Reverts with
    InvalidSliceParameters
    if out-of-bounds.
  • Used internally by decode to remove the first 4 bytes (or any other arbitrary slice).

  • Parameters:

    • data_: The original bytes array to slice.

    • start_: The offset in data_ to begin slicing.

    • length_: Number of bytes to copy into the new array.

  • Return:

    • result_: A newly allocated bytes array of size length_, containing the requested slice.

  • Errors:

    • InvalidSliceParameters(): Thrown if start_ + length_ exceeds the length of data_.

  • Inherited Contracts and Interfaces

    Constants and State Variables

    Constructor

    External Functions

    initialize(address owner_)

    decode(bytes calldata calldata_)

    Internal and Private Functions

    _authorizeUpgrade(address)

    _slice(bytes memory data_, uint256 start_, uint256 length_)

    Errors

    InvalidSliceParameters()

    Summary

    address public s_escrowVoteManager;
    constructor() {
        _disableInitializers();
    }
    function initialize(address owner_, address escrowVoteManager_) external initializer
    function createGauge(
        address owner_,
        address eywa_,
        IDistributionCreator.CampaignParameters calldata campaignParameters_
    ) 
        external 
        returns (address)
    function _authorizeUpgrade(address) internal override onlyOwner
    constructor() {
        _disableInitializers();
    }
    function initialize(address owner_) external initializer
    function decode(bytes calldata calldata_) external pure returns (
        bytes memory m_calldata,
        address m_target,
        uint64 m_chainId
    )
    function _authorizeUpgrade(address) internal override onlyOwner
    function _slice(
        bytes memory data_, 
        uint256 start_, 
        uint256 length_
    ) private pure returns (bytes memory result_)
    Currently, the collection is available on the Aurora and Arbitrum networks:

    On the Aurora network, the collection is available for trading within our Telegram communities (Links to Telegram chats for trading Eywa NFTs: English speaking region CIS region).

    On the Arbitrum network, the collection is available for trading on OpenSea.

    Here is the Eywa NFT collection address in Aurora and Arbitrum.

    The EYWA NFT collection is composed of ERC-721 tokens with the following unique functions:

    • Container function for storing up to 1 500 000 EYWA tokens

    • Merge function that allows you to increase the size of the container and the rarity of the NFT by combining multiple NFTs of one level into one rarer NFT

    • CrossCurve DAO vote multiplier function via veEYWA

    Each NFT in the collection functions as a container for EYWA tokens. You can attach both unlocked and locked (in vesting safes*) tokens to the NFT. This allows the user to sell blocked EYWA tokens at any time.

    The capacity of each NFT is the maximum number of EYWA tokens it can contain and depends on the rarity of the NFT. The highest capacity — 1 500 000 EYWA — is reserved for the Infinity rarity level NFTs. In the Aurora chain, you can see your current balance of token in the container. Once migrated to the Arbitrum chain, the tokens will be separated from the NFT and can be received as vesting safes via the Claim portal after the TGE.

    For details, see the table below:

    Rarity
    Capacity per NFT

    common

    500

    uncommon

    3 000

    rare

    25 000

    Several NFTs of the same type can be merged to create a single NFT with a higher rarity level. This will also merge all of the tokens contained in the source NFTs.

    Multiplier table for NFT merging:

    Rarity
    Merge multiplicator
    You will receive

    common

    5

    1 uncommon

    uncommon

    7

    1 rare

    To vote in the EYWA DAO, users must lock EYWA tokens — the longer the lock period, the more voting power the user gets. Using EYWA NFTs can also increase voting power. Each NFT can increase the number of available votes by the maximum number of tokens it can contain.

    For details, see the table below:

    Rarity
    Maximum amount of tokens for boost
    Multiplier for veEYWA votes

    common

    500

    1.006

    uncommon

    3 000

    After the NFT collection is migrated to the Arbitrum chain, all of the above functions will become available. Before the TGE, we will open up a bridge to move the NFTs from Aurora to Arbitrum, as well as the NFT Manager to fully engage with all of the functions of the NFTs.

    The NFT Manager will ensure access to tokens contained in the NFTs, which will be separated from their containers after the migration to Arbitrum and be put together in each user’s wallet. Users will be able to put tokens into vesting safes and keep rEYWA in the NFTs.

    NFT collection description

    Eywa NFT Characters

    The characters in the collection are unique creations, drawing inspiration from beloved science fiction universes.

    The Magician Crafted from leaves and various flora types, the magician is inspired by the Star Wars universe and Elemental creatures, as well as ancient Roman and Greek mythology.

    The Dryad This character is inspired by ancient Greek myths, aliens, and the golden era of science fiction, presenting a stunning fusion of a wood nymph with a World of Warcraft (WoW) hero.

    The Ent Assembled from tree bark and roots, the Ent is inspired by the Ents from the Lord of the Rings (LOTR) universe, Swamp Thing from DC Comics, and Groot from Marvel.

    The Spider The spider character embodies an aggressive, dynamic figure, combining an arachnid with a trickster — a mix of Baal from Diablo II, Monsters, Inc., and other characters, infused with elements of insects and alien life forms.

    We have deliberately directed our design team to embrace a “fairytale” aesthetic in the creation of our characters' likenesses. Regardless of age, we all cherish a touch of magic in our lives.

    Echoing the words of Steve Jobs: “Follow your heart, stay hungry, stay foolish!” we are committed to developing the finest cross-chain product on the market. Thank you for your support!

    Common
    Uncommon
    Rare
    Legendary
    Infinity

    The utility of EYWA NFTs

    Container

    * Vesting safes are objects containing EYWA tokens that are blocked for a certain period of time based on the rules of the funding round (detailed information about the rules of each round and vesting periods are available ).

    Merge

    veEYWA voting multiplier

    For example, a user with 100,000 EYWA tokens can use one Legendary NFT to give his votes a 2.8 multiplier, since a Legendary NFT type can cover up to 250,000 tokens, or 4 Rare NFTs a 1.3x multiplier each (since each Rare NFT can only cover 25,000). Users can use any number and combination of NFTs for veEYWA vote multipliers to cover all of their holdings of EYWA.

    Migration to Arbitrum

    blockchain A
    , a contract calls a bridge contract function to send data to
    blockchain B
    . The bridge contract emits an event, which is picked up by its off-chain service. This service then creates a transaction containing the necessary data for the corresponding bridge contract on
    blockchain B
    . Upon receiving the transaction, the bridge contract verifies its validity and then invokes the target contract function, passing along the data received from
    blockchain A
    .

    One of the core challenges lies in the fact that the bridge service operates outside the blockchain environment and therefore cannot be verified on-chain. Different bridge protocols address this issue in different ways.

    CrossCurve Consensus Bridge, however, introduces a more comprehensive approach. It is not meant to replace existing protocols - instead, it integrates and leverages their mechanisms, creating a unified and verifiable cross-chain communication layer.

    • The sender initiates a message in the source network by calling the CrossCurve Gatekeeper contract.

    • Depending on the destination chain, the Gatekeeper prepares and executes parallel message dispatches through multiple supported protocols. One of these protocols transmits the full message payload, while the others send verification proofs to confirm message authenticity.

    • Each protocol, following its standard cross-chain messaging process, independently delivers its data to the CrossCurve Receiver contract in the destination network.

    • The Receiver collects the received message instances and emits events as they arrive.

    • The external service CrossCurve Pusher monitors these events. Once the original message and a sufficient number of verification confirmations are detected, it submits an execution transaction to the CrossCurve Receiver contract.

    • Upon receiving the transaction from CrossCurve Pusher, the Receiver verifies the existence of the original message and all required confirmations from other protocols.

    • If validation is successful, the verified message is then delivered to its designated recipient.

    CrossCurve Consensus Bridge provides a truly secure mechanism for cross-chain messaging.

    Its minimal configuration requires three sovereign cross-chain protocols.

    Even in this base setup, an attacker would need to gain simultaneous control over at least two out of the three protocols to compromise a message — making unauthorized interference practically infeasible.

    Decentralization is one of the most effective defenses against censorship.

    However, in many cross-chain systems, services are often built on specific infrastructure stacks, which introduces potential points of control and censorship.

    CrossCurve Consensus Bridge eliminates this issue by leveraging sovereign protocols that operate independently from one another.

    For an adversary to block or alter message delivery through the bridge, they would need to control more than 50% of the protocols participating in the message channel (in the minimal setup, that means controlling two out of three).

    The consensus of independent protocols ensures not only security but also fault tolerance in message transmission. Even in its minimal configuration, if one of the three protocols becomes temporarily unavailable, the remaining two are sufficient to keep the CrossCurve Consensus Bridge fully operational.

    In the rare event of a deadlock — when one or more bridges within the consensus experience prolonged downtime, potentially locking assets that relied on the consensus bridge — the situation remains recoverable. The CrossCurve DAO can replace the affected protocols in the consensus bridge of the impacted chain by approving a dedicated governance proposal.

    The CrossCurve Consensus Bridge is engineered for maximum security through the use of consensus among independent bridge protocols for data transmission.

    Yet even the most secure systems can face potential vulnerabilities. The most common vector of attack targets governance mechanisms — an adversary might attempt to alter the composition of participating bridges, making it easier to compromise a single one.

    In CrossCurve Consensus Bridge, such a scenario is structurally impossible.

    Bridge configuration across all chain pairs is managed exclusively by the CrossCurve DAO. Any modification requires explicit community approval. The voting process lasts 7 days, and even after a proposal passes, the new configuration takes effect only after 24 hours, providing an additional safeguard and ensuring transparent governance.

    This underlines the critical role of the CrossCurve DAO in maintaining decentralization across cross-chain messaging.

    We believe that greater decentralization and resilience can be achieved when ecosystem participants — those advocating for transparency, stability, and security — become active members of the CrossCurve DAO. Their participation strengthens governance integrity and makes malicious decisions significantly harder to pass.

    This is the foundation for building advanced cross-chain applications.

    Through the Consensus Bridge, dApps gain a reliable communication layer between their instances deployed across different blockchains - or with APIs of other applications operating in separate networks.

    Cross-chain token transfer applications using any combination of lock/mint or burn/mint models can rely on the Consensus Bridge as a trustless verification layer.

    It provides accurate and verifiable information about token locking, minting, unlocking, or burning events across different blockchains.

    The Consensus Bridge integrates seamlessly into the LayerZero cross-chain verification system.

    This is achieved through a wrapper module called SuperDVN, which externally behaves like a standard DVN but internally performs multi-protocol consensus verification for enhanced security and reliability.

    Currently, the CrossCurve Consensus Bridge supports the following messaging protocols:

    • CrossCurve Oracle Network

    • Layer Zero

    • Axelar

    • Router Protocol

    The integration with the Consensus Bridge is planned to be permissionless. However, the protocol is currently operating in an experimental mode. If you’d like to connect, please contact us vc@eywa.fi

    To send a message to a recipient on another chain, you need to:

    1. Prepare the calldata for the target contract function with the required parameters.

    2. Call the sendData function on the CrossCurve Gatekeeper contract:

    To configure the bridge, use the following contract addresses.

    Network
    CrossCurve Receiver Address
    CrossCurve Gatekeeper Address

    Ethereum Sepolia Testnet

    Arbitrum Sepolia Testnet

    Overview

    Architecture

    Basic cross-chain schema

    sendData(
            bytes calldata data,
            bytes32 to,
            uint64 chainIdTo,
            bytes[] memory currentOptions
        ) external nonReentrant returns(uint256 fee)

    Consensus Bridge schema

    Advantages

    Security

    Censorship Resistance

    Resilience

    Governance Protection

    Capabilities

    Cross-Chain Messaging

    Cross-Chain Token Transfers

    Foundation for SuperDVN

    Supported Protocols

    Integration and Connection

    Contracts

    For proper operation, the contracts must be deployed on both the source and destination blockchains.

    Owner-Based Access Control: Critical functions (like upgrading the contract and updating campaign parameters) are restricted to the owner.

  • Reward Notification: The notifyRewardAmount function can only be invoked by the authorized escrow vote manager, ensuring a controlled flow of rewards.

  • Campaign Parameters: The gauge uses dynamic campaign parameters (s_campaignParameters) to manage reward distribution schedules and amounts, which can be updated by the owner if needed.

  • By implementing IGaugeV1, GaugeV1 provides a standardized interface for initializing, updating campaign parameters, and receiving new reward amounts within the CrossCurve ecosystem.


    • UUPSUpgradeable (OpenZeppelin): Enables upgradeability under the UUPS (Universal Upgradeable Proxy Standard) pattern, restricted to the contract owner.

    • OwnableUpgradeable (OpenZeppelin): Provides ownership logic, limiting certain state changes (e.g., upgrading, updating parameters) to the contract owner.

    • IGaugeV1: Interface defining core functions (e.g., initialize, updateCampaignParameters, notifyRewardAmount) and events (RewardNotified, CampaignParametersUpdated) for the gauge contract.

    Additional External References:

    • SafeERC20, IERC20 (OpenZeppelin): Library and interface for safe ERC20 token transfers.

    • IEscrowVoteManagerV1: Tracks and authorizes reward notifications, ensuring that only the designated manager can call notifyRewardAmount.

    • IDistributionCreator: Contract on Arbitrum that actually creates or schedules distribution campaigns (Merkl distributions).

      • The contract uses DISTRIBUTION_CREATOR with a known address (0x8BB4C975Ff3c250e0ceEA271728547f3802B36Fd) on Arbitrum.


    • EPOCH_DURATION: The duration of an epoch (1 week). Used to align reward distribution campaigns with discrete time intervals.

    • DISTRIBUTION_CREATOR: The address of the Merkl distribution contract on Arbitrum. This contract is responsible for orchestrating reward distributions once campaigns are created.


    • s_escrowVoteManager (address) Address of the escrow vote manager contract, which is authorized to call notifyRewardAmount.

    • s_eywa (address) The EYWA token address used for rewards distribution.

    • s_campaignParameters (IDistributionCreator.CampaignParameters) Holds the current campaign parameters for distributing rewards. These parameters include data like amount, duration, start timestamp, and distribution logic, which can be updated by the owner.


    • Description: Disables contract initializers to prevent multiple initializations. Enforces that initialize can be called only once in a UUPS upgradeable context.


    • Description:

      • Initializes the gauge contract by setting the owner, escrow vote manager, EYWA token address, and the initial campaign parameters for rewards.

      • Can only be called once, marked by the initializer modifier from OpenZeppelin upgradeable patterns.

    • Parameters:

      • owner_: The address designated as the contract owner.

      • escrowVoteManager_: The address of the escrow vote manager, authorized to call notifyRewardAmount.

    • Effects:

      • Calls __UUPSUpgradeable_init() and __Ownable_init(owner_) to set up UUPS upgrade and ownership.

      • Assigns s_escrowVoteManager and s_eywa


    • Description:

      • Allows the contract owner to update the gauge’s campaign parameters.

      • The newly provided parameters (newCampaignParameters_) overwrite the existing ones in s_campaignParameters.

    • Parameters:

      • newCampaignParameters_: The updated distribution parameters (e.g., new schedule or amounts) for this gauge.

    • Events:

      • Emits CampaignParametersUpdated(address(this), oldCampaignParameters, newCampaignParameters_) to log the changes.


    • Description:

      • Notifies the gauge of a newly available amount_ of EYWA tokens to be distributed as rewards.

      • Can only be called by s_escrowVoteManager.

      • The function transfers amount_ from the caller to this gauge, checks if the resulting balance is sufficient to meet the minimum distribution threshold, and if so, triggers the distribution campaign via DISTRIBUTION_CREATOR.createCampaign(...).

    • Parameters:

      • amount_: The amount of EYWA tokens to be added for distribution.

    • Checks & Logic:

      1. Verifies msg.sender == s_escrowVoteManager, otherwise reverts with UnauthorizedCaller().

      2. Transfers amount_ of EYWA from the caller to the contract.

    • Events:

      • RewardNotified(amount_) logs the newly notified reward amount.


    • Description:

      • Ensures that only the contract owner can authorize upgrades.

      • Enforced by the UUPSUpgradeable pattern.


    1. RewardNotified(uint256 indexed amount)

      • Emitted when new rewards are notified to the gauge, indicating the total tokens added.

    2. CampaignParametersUpdated( address indexed gauge, IDistributionCreator.CampaignParameters oldCampaignParameters, IDistributionCreator.CampaignParameters newCampaignParameters )

      • Logged when the owner updates the gauge’s distribution campaign parameters.


    • UnauthorizedCaller()

      • Thrown if a function restricted to s_escrowVoteManager or onlyOwner is called by an unauthorized address.


    GaugeV1 is an upgradeable contract that manages reward distributions for a specific pool or strategy within the CrossCurve ecosystem. By connecting to an Escrow Vote Manager, it ensures only authorized parties can add new rewards (notifyRewardAmount). Through DistributionCreator on Arbitrum, it transforms these rewards into time-bound distribution campaigns. The contract owner can update campaign parameters if needed, while all major functionalities (initialization, upgrade, parameter updates) remain protected by ownership and authorized checks.

    Overview

    uint256 public constant EPOCH_DURATION = 1 weeks;
    IDistributionCreator public constant DISTRIBUTION_CREATOR = IDistributionCreator(0x8BB4C975Ff3c250e0ceEA271728547f3802B36Fd);
    constructor() {
        _disableInitializers();
    }
    function initialize(
        address owner_,
        address escrowVoteManager_,
        address eywa_,
        IDistributionCreator.CampaignParameters calldata campaignParameters_
    ) 
        external
        initializer
    function updateCampaignParameters(
        IDistributionCreator.CampaignParameters calldata newCampaignParameters_
    ) 
        external 
        onlyOwner
    function notifyRewardAmount(uint256 amount_) external
    function _authorizeUpgrade(address) internal override onlyOwner

    Inherited Contracts and Interfaces

    Constants

    State Variables

    Constructor

    External Functions

    initialize(...)

    updateCampaignParameters(...)

    notifyRewardAmount(uint256 amount_)

    Internal and Private Functions

    _authorizeUpgrade(address)

    Events

    Errors

    Summary

    Field
    Type
    Description

    query

    object

    Echo of request parameters (params, slippage)

    route

    array

    Ordered list of route steps (pass entire object to /tx/create)

    amountIn

    string

    Input amount in smallest token units

    amountOut

    Fee objects (sourceFee, deliveryFee)

    Field
    Type
    Description

    token

    string

    Token address the fee is denominated in

    amount

    string

    Fee amount in smallest token units

    Gas estimate objects (txs array items)

    Field
    Type
    Description

    chainId

    number

    Chain where gas will be consumed

    gasConsumption

    number

    Estimated gas units

    Route step objects (route array items)

    Each step describes one leg of the swap:

    Field
    Type
    Description

    chainId

    number

    Chain where this step executes

    type

    string

    Step type (e.g. "bridgeIn")

    When calling /tx/create, pass the route object as the routing field. For /routing/scan/stream, this is the simulation object from each NDJSON line. For /routing/scan, this is an item from the response array. Do not modify or cherry-pick fields from it.


    0xA17aa5eE656849221C8d9d062894e1145CbdA864

    Obtaining veEYWA and Calculating the Boost

    In order to become a participant in CrossCurve DAO, you need to lock your EYWA tokens or EYWA NFT along with them.

    Users can lock EYWA tokens for up to 3 years, receiving veEYWA — their voting power in the DAO. The longer the lock duration and the higher the NFT rarity, the greater the participant’s voting power (influence) in the DAO and the more incentives and benefits they gain.

    Voting power decreases as the token unlock time approaches unless the lock is extended. This encourages long-term commitment, strengthens the project’s stability, and allows participants to actively influence its development.

    EYWA NFTs multiply veEYWA, increasing voting power, income, and a user's influence in the DAO. To do this, you must attach EYWA tokens or one or more Vesting Safes containing EYWA tokens to an EYWA NFT.

    A Vesting Safe is a special contract from the CrossCurve team that stores locked EYWA tokens. The tokens in the safe unlock according to an algorithm matching the type of round in which they were received.

    The is a smart contract where owners lock their EYWA tokens for various durations. The purpose of locking is to obtain voting power in the form of veEYWA. Voting power depends on the lock duration: the longer the lock, the greater the voting power for the same number of locked tokens.

    • Maximum lock duration: 3 years (156 weeks), providing the maximum ratio: 1 locked token = 1 vote.

    • Minimum lock duration: a few days (until the end of the current epoch). For example, 2 days give 2/1092 of a vote.

    Example: 156 tokens locked for one week give 1 vote.

    Where T is the lock time in weeks (Formula 1)


    When working with the smart contract, note that the contract automatically "rounds" the submitted lock date to the end of the previous epoch (Thursday 00:00 UTC). This means that if a date falls on a Friday, Saturday or Monday, the smart contract will set the lock time to the preceding Thursday.

    To accommodate this behavior, the website interface for interacting with the sends a especially calculated date, to the smart contract:

    where:

    - the current time,

    - time remaining until the end of the current epoch,

    - the duration of one epoch (1 week),

    n - the number of weeks the user wants to lock tokens.

    Additionally, the total lock time cannot exceed 156 epochs (weeks).

    Due to these mechanics, achieving a value equal to 1 is nearly impossible. The closest approximation can only occur if a locking transaction is sent for 156 weeks immediately after the start of a new epoch, such as Thursday at 00:00:01 UTC. In that case:

    However, time constantly moves forward, and even a minute later:

    Whether or not to continuously update the lock time, and at what intervals, is a decision each DAO participant must make individually based on their own objectives and intentions.

    Where:

    • is the number of tokens locked by the owner i, considering NFT boosts,

    • is the lock-time coefficient for user i,

    • n is the number of users who have locked their EYWA tokens

    (Formula 2)


    EYWA DAO NFT is an ERC-721 NFT created when EYWA tokens are locked in the .

    Key features:

    • Attaching assets: Each EYWA DAO NFT can have EYWA tokens, Vesting Safes, and other EYWA NFTs attached to it.

    • Obtaining veEYWA: The obtained veEYWA is automatically tired to the corresponding EYWA DAO NFT.

    • Multiple ownership: A user can own an unlimited number of EYWA DAO NFT.

    Thus, EYWA DAO NFT serves as a hub for managing your locked assets and voting power in the DAO, providing flexibility and scalability in project governance.


    When creating an EYWA DAO NFT in the Locker, you can lock EYWA tokens in various states When transferring to the Locker:

    1. EYWA tokens (standard ERC-20)

    • Ownership is transferred to the contract.

    1. Vesting Safe contracts with direct ownership (held in the user’s wallet)

    • Ownership of the Vesting Safe contract is transferred to the Locker.

    1. Vesting Safe contracts with ownership via an NFT (Vesting Safe contracts attached to an EYWA NFT)

    • The Vesting Safe is detached from an EYWA NFT and transferred to the Locker.

    • The EYWA NFT ownership is also transferred to the Locker.

    1. ERC-20 EYWA tokens with ownership via an NFT (EYWA tokens attached to an EYWA NFT)

    • Tokens are detached from an EYWA NFT and transferred to the Locker.

    • Ownership of an EYWA NFT is also transferred to the Locker.

    The calculates the amount of veEYWA based on the total number of EYWA tokens locked, including both standard ERC-20 tokens and those in the Vesting Safe.

    • You cannot create an EYWA DAO NFT by adding an empty EYWA NFT to the Locker.

    • You can attach no more than 100 Vesting Safes and 100 EYWA NFTs to one EYWA DAO NFT.


    You can modify an EYWA DAO NFT in several ways:

    Adding additional EYWA tokens:

    • You can lock more EYWA tokens in any of the ways described above at the time of creating an EYWA DAO NFT.

    Adding/attaching empty EYWA NFTs:

    • You can attach additional empty EYWA NFTs to an existing EYWA DAO NFT.

    Removing/detaching EYWA NFTs:

    • You can detach an EYWA NFT from an EYWA DAO NFT, returning them to the user’s ownership.

    Extending the lock duration of tokens:

    • You can extend the lock duration of already locked EYWA tokens to increase voting power.


    EYWA NFT Collection

    A released collection EYWA NFTs allows users to increase their voting power in the DAO. To do this, you must attach your NFTs from this collection in the. When sending NFT tokens, they are locked under different conditions than standard EYWA tokens.

    Attaching and Detaching EYWA NFTs

    • Attaching EYWA NFTs:

      • When one or more EYWA NFTs are added to an EYWA DAO NFT, a boost is applied to the locked EYWA tokens, increasing voting power.


    Rarity
    Multiplier for veEYWA (MV)
    Capacity per NFT (CT)

    MV (Multiplier for veEYWA): A multiplier that increases veEYWA.

    CT (Capacity per NFT): The maximum number of EYWA tokens affected by an NFT.


    total number of tokens locked by the owner

    number of tokens of the same rarity locked by the owner

    - this is the total number of tokens that can be affected by NFT boosts (Formula 3)

    If is greater than or equal to , then the overall boost formula is:

    (Formula 4)

    If is greater than , it means the volume of tokens that could theoretically be influenced by the NFT boost is greater than the owner’s tokens. Therefore, we must fairly allocate the available token volume for the greatest results. For that, we use the following algorithm:

    1. =*1500000

    2. If is less than or equal to , then = *3;

    3. Else: = *3; =-

    The final is then used to determine the amount of veEYWA votes owned by the token holder.

    1. Example: 1 000 000 tokens and one Legendary NFT are locked (=1). Using the Formula 3: =0*500+ 0*3000+0*25000+1*250000+0*1500000 = 250000

    Since is greater than , we shall use the Formula 4:=1000000-250000+0*500*1.006+ 0*3000*1.036++0*25000*1.3+1*250000*2.8+0*1500000*3 = 750000+700000=1450000

    1. Example. 1 000 000 tokens and ten Legendary NFTs are locked (=10). Using the Formula 3: =0*500+ 0*3000+0*25000+10*250000+0*1500000 = 2500000

    Since is less than , we cannot use the Formula 4. Therefore, we shall use the following algorithm:

    ==1 000 000

    =*1500000=0

    is greater than , therefore

    = *3=0; =- = 1 000 000

    =*250000 = 10* 250 000 = 2 500 000

    If is less than or equal to , therefore the final calculations are equal to: =+ *2.8 = 0+1 000 000 *2.8 = 2 800 000

    1. Example. 2 000 000 tokens,1 Infinity NFT ( =1) and 10 Legendary NFTs are locked(=10). Using the Formula 3, we get: =0*500+ 0*3000+0*25000+10*250000+1*1500000 = 4 000 000

    Since is less than , we cannot use the Formula 4. Therefore, we shall use the following algorithm:

    ==2 000 000

    =*1500000 =1*1 500 000

    is greater than , therefore

    = *3=4 500 000; =-=2 000 000 -1 500 000 = 500 000

    =*250000=10*250 000 = 2 500 000

    is less than , therefore the final calculations are equal to: =+ *2.8=4 500 000 + 500 000*2.8 = 5 200 000


    The CrossCurve protocol provides a unique system that allows reaching a maximum number of votes — 2 820 221 429. This figure is achieved through a combination of EYWA tokens and NFT multipliers, as well as their optimal distribution according to capacity.


    In the new version of our NFT collection, a “freeze” mechanism has been introduced. After detaching tokens from an NFT, a 4-hour period is activated during which the NFT cannot be moved. This prevents the aforementioned unscrupulous practice: if a user attempts to detach tokens from an NFT being sold. They cannot finalize the deal since the NFT cannot be transferred to the buyer. As a result, only buyers who possess tokens will be able to purchase the NFT, reducing the risk of front-running.

    Furthermore, the mechanism also applied to cases where tokens are locked in the DAO Locker. This means that when locking an NFT in the Locker, the same 4-hour “freeze” applies. This delay is necessary to ensure the system’s security and prevent abuse. Users should keep this feature in mind to avoid misunderstandings. It’s important to plan NFT-related actions with a “freeze” period in mind.

    Locker Interface

    Locker Interface Description

    The Locker is a smart contract where holders lock their EYWA tokens, EYWA token safes, EYWA NFTs with EYWA tokens, and project safes for various durations. The purpose of such locking is to obtain project votes - veEYWA voting power. A user’s voting power depends on the duration for which their tokens are locked. The maximum lock period is 3 years (156 weeks), which provides the highest ratio: 1 locked token = 1 vote. More details can be found here.

    To start using the CrossCurve application, navigate to the Locker page under the DAO section. Click «Connect wallet», select a suitable wallet from the list, and confirm the connection, ensuring you are on the official page: https://app.crosscurve.fi/locker

    On the Locker page, the current CrossCurve DAO statistics are displayed:

    • Total locked EYWA - the total number of locked EYWA tokens

    • Total supply veEYWA - the total issued veEYWA tokens

    For detailed mechanics on how voting power is calculated when locking EYWA tokens, click Read docs.

    To create a new EYWA token lock, click Lock Tokens

    The page Create token lock contains the following elements:

    • Now you have - the number of created locks and the total veEYWA amount in these locks.

    • Amount to lock - the number of EYWA tokens from your wallet balance for the new lock, increasing the total veEYWA amount.

    • Select your vested EYWA to receive veEYWA - an option to select vesting safes for the new lock, adding EYWA tokens from vesting safes to increase the total veEYWA amount.

    The Create Token Lock application allows you to add EYWA tokens from your wallet, vesting safes, and the EYWA NFT container either separately or simultaneously*.

    You can specify the number of EYWA tokens from your wallet balance in the Amount to lock field, select vesting safes in the Select your vested EYWA to receive veEYWA menu, and select EYWA tokens from NFT containers in the Select your EYWA NFTs and boost voting power menu. After selecting the desired amount of EYWA tokens, vesting safes, and EYWA NFT containers, the application calculates the total locked EYWA tokens in the You lock field and the veEYWA voting power based on the selected lock duration in the You’ll get field.

    To create a lock with EYWA tokens from your wallet balance, enter the number of locked tokens in the Amount to lock field and select the lock duration using the slider in the Lock time field. The possible lock duration ranges from 0 to 156 weeks.

    Example: 156 locked tokens for a week provide 1 vote. More details can be found in the , but the simple explanation is:

    • 1 EYWA, locked for 3 years = 1 veEYWA

    • 1 EYWA, locked for 2 years = 0.66(6) veEYWA

    • 1 EYWA, locked for 1.5 years = 0.5 veEYWA

    • 1 EYWA, locked for 1 year = 0.33(3) veEYWA

    The longer you lock your EYWA, the greater your Voting Power and the bigger the boost you can achieve. Voting power is expressed in the number of veEYWA.

    After ensuring the number of locked tokens and the lock duration, the amount of voting power in veEYWA tokens obtained will be displayed in the You’ll get field. Below, the current CrossCurve DAO statistics will be displayed:

    • Total locked EYWA - the total number of locked EYWA tokens in DAO

    • Total supply veEYWA - the total issuance of veEYWA tokens

    • Average EYWA NFT boost - the average boost multiplier obtained for locking an EYWA NFT, depending on the rarity of the NFT being locked (more details )

    To create a lock, click Create Token lock and sign the transaction in your wallet. If you do not have EYWA tokens in your wallet, use the direct Buy token link for purchase.

    After successful on-chain conformation of the transaction, detailed information about the existing locks will be displayed on the page:

    To add EYWA tokens from vesting safes to the newly created lock, select safes by clicking Select your vested EYWA to receive veEYWA in the Create Token Lock menu. The possible ranges from 0 to 156 weeks.

    In the modal window, you will see a list of all available Vested EYWA safes and information about the total number of safes Total in wallet, as well as the sum of all EYWA tokens in them.

    Select a safe (or a group of safes of the same type) to create a lock by clicking the checkbox to the left of the safe. The Locker will display the number of selected safes and EYWA tokens in them in the You selected window. A maximum of 100 safes can be selected per transaction when creating one lock*. To continue, click Lock selected.

    Returning to the Create Token Lock menu, the number of selected safes and EYWA tokens in them will be displayed in the Selecting field.

    To add Vested EYWA safes to the lock, select the lock duration using the slider in the Lock time field. The possible ranges from 0 to 156 weeks. After selecting the lock duration, the You’ll get field will display the total amount of voting power received in veEYWA tokens. If you need to create a lock only from vesting safes, click Create Token lock and sign the transaction in your wallet.

    To add EYWA tokens from EYWA NFT containers to the newly created lock, click Select your EYWA NFTs and boost voting power in the Create Token Lock menu. The possible ranges from 0 to 156 weeks.

    In the modal window, you will see a list of all available EYWA NFTs in the connected wallet, sorted by their rarity, along with detailed information:

    • EYWA tokens - the number of EYWA tokens attached to the NFT container (more details )

    • Capacity - the capacity of the NFT container (more details )

    • veEYWA Boosted - NFT boost (more details )

    If there are no EYWA NFTs in the connected wallet, use the quick buy link in the Aurora () or Arbitrum ()

    Select an NFT* (or a group of NFTs of the same rarity) to create a lock by clicking the checkbox to the left of the NFT. The Locker will display the number of selected NFTs and EYWA tokens in containers in the Selected field. A maximum of 100 NFTs can be selected per transaction when creating one lock. To continue, click Lock EYWA NFTs.

    • If you have detached EYWA tokens from the EYWA NFT container, that EYWA NFT will have a 4-hour freeze period. Only after the timer has expired can you add that NFT to the lock.

    • If the EYWA NFT container has EYWA tokens without vesting attached, you must them in EYWA NFT Manager (use quick ) so that this NFT becomes available for adding to the lock. After detaching EYWA tokens, this NFT will be frozen for 4 hours (frontrun protection).

    Returning to the Create Token Lock menu, the line Selecting will display the number of selected NFTs and the number of EYWA tokens in the containers, and in the line Average EYWA NFT boost, the average boost for vote will be calculated depending on the rarity of the selected NFTs.

    To create the EYWA NFTs lock, select the lock duration using the slider in the Lock time field. The possible ranges from 0 to 156 weeks. After selecting the lock duration, the You’ll get field will display the amount of voting power boost obtained (more details ). If you need to create a lock only from EYWA NFTs, click Create Token lock and sign the transaction in your wallet.

    If the Amount to Lock field is set to 0 EYWA and no EYWA in vesting is selected, and you have selected an EYWA NFT with no EYWA tokens attached, a message will appear: Unselect NFTs with 0 EYWA or add EYWA tokens. In this case, to create the lock, you must fulfill one of the following conditions:

    • Unselect the NFT with 0 EYWA tokens in the selection menu Select your EYWA NFTs and boost voting power

    • Add EYWA tokens from your wallet balance in the Amount to lock, or add EYWA tokens with vesting in the selection menu Select your vested EYWA to receive veEYWA.

    During the lock period, you can manage accrued rewards and add EYWA tokens and EYWA NFTs to the lock.

    To start working using the CrossCurve application, go to the Locker page in the DAO section. Click «Connect wallet», select the appropriate wallet from the list, and confirm the connection, ensuring you are on the official page:

    On the Locker page, detailed information about existing locks will be displayed:

    • id - D number of EYWA DAO NFT (ID number assigned after creating a new lock through Create lock)

    • Locked EYWA - the number of EYWA tokens in the EYWA DAO NFT safe

    • NFTs - the number of EYWA NFTs inside the lock

    1. The label Available, means that this EYWA DAO NFT (lock) is free for transfer, sale, and unlocking if the lock period has expired.

    2. The snowflake icon means that the transfer is frozen, and this EYWA DAO NFT cannot be moved, sold, or unlocked. Freezing can occur for two reasons:

    The Available status means that the EYWA DAO NFT can be transferred, sold, or unlocked (if the lock period has ended).

    The status with the Unfreeze link next to it means that the transfer is frozen - this lock is currently participating in voting for the current or previous epoch. To transfer, you must cancel the vote. To cancel the vote, click Unfreeze and confirm the vote cancellation in the modal window.

    To confirm vote cancellation in the current/previous voting rounds, click Reset votes and sign the transaction in your wallet.

    After confirming the transaction on-chain, the EYWA DAO NFT will become available for transfer.

    The status with the Timer icon means that the EYWA DAO NFT is unavailable for transfer after detaching the EYWA NFT. You must wait 4 hours (front-running protection) before the EYWA DAO NFT can be moved.

    Once the timer expires, the transferability status will change to Available.

    1. To add accrued Staking rewards to the lock, click Compound and sign the transaction in your wallet. The EYWA Staking rewards tokens will be added to the lock for which they were received, for the same duration as the existing lock.

    1. To add EYWA tokens to an existing lock and extend it, click Manage.

    Information about the selected lock will be displayed:

    • Unlocking on - the lock expiration date

    • Already locked - the number of locked EYWA tokens and vesting safes

    • Owned - voting power in veEYWA tokens

    To view detailed information about existing vesting safes, click View

    In the Vested EYWA modal window, detailed information about your vesting safes will be displayed:

    • The round name when the safe was received and the number of identical vesting safes (more details )

    • All tokens - the number of EYWA tokens in the vesting safe

    • Unlocked EYWA - the number of EYWA tokens received from the vesting safe

    2.1 To add EYWA tokens to the lock, enter the amount in the Amount to compound field.

    To update the lock duration, select Update time lock and set a new lock duration using the slider.

    After entering the amount and selecting the lock duration, the application will display the total number of EYWA tokens ready for locking in the You lock field and the voting power (veEYWA) obtained after the changes in the You’ll get field. To update the lock, click Update Locker and confirm the transaction in your wallet.

    2.2 To add EYWA tokens from EYWA NFT containers to the lock and receive a voting power boost, click Select your EYWA NFTs and boost voting power in the Manage Locker menu.

    In the modal window, you will see a list of all EYWA NFTs available in your connected wallet, sorted by rarity, along with detailed information. If there are no EYWA NFTs in your connected wallet, use the quick purchase link for Aurora () or Arbitrum ()

    Select an NFT (or a group of NFTs of the same rarity) to add to the lock by clicking the checkbox next to the NFT. The Locker will display the number of selected NFTs and EYWA tokens in the containers in the Selected field. A maximum of 100 NFTs can be selected per transaction when adding NFTs to a lock. To continue, click Lock EYWA NFTs

    Returning to the Manage Locker menu, the Selecting field will display the number of selected NFTs and EYWA tokens in the containers. To update the lock duration, select Update time lock and set a new lock duration using the slider.

    After selecting the lock duration, the application will display the total number of EYWA tokens ready for locking in the You lock field, the voting power (veEYWA) obtained after the changes in the You’ll get field, and the average voting power boost in the Average EYWA NFT boost. To update the lock, click Update Locker and confirm the transaction in your wallet.

    The EYWA NFT in locks window displays detailed information about EYWA NFTs locked in the DAO:

    • Transferable - lock transferability status (more details here)

    • Locked EYWA NFTs - the number of EYWA NFTs locked in the DAO

    • Unboosted tokens - the number of EYWA tokens that were not counted in the boost calculation due to container capacity limitations.

    • Average boost - the average boost value obtained for the EYWA NFT lock (more details )

    To transfer an NFT from the lock, click Withdraw

    In the modal window, you will see a list of EYWA NFTs locked in the DAO, sorted by rarity and detailed information:

    • Capacity - NFT container capacity (more details here)

    • veEYWA Boosted - NFT boost (more details here)

    If there are no EYWA NFTs in your connected wallet, use the quick purchase link for Aurora () or Arbitrum ()

    Select an NFT* (or a group of NFTs of the same rarity) to unlock by clicking the checkbox next to an NFT. A maximum of 100 NFTs can be unlocked per transaction.

    To confirm vote cancellation in the current/previous voting rounds, click Reset votes and sign the transaction in your wallet.

    After confirming the transaction on-chain, the EYWA NFT will become available for unlocking.

    To continue unlocking EYWA NFTs, click Withdraw EYWA NFTs and confirm the transaction in your wallet.

    1. Once the lock period ends, the Unlock button will become available. To unlock the EYWA DAO NFT and manage safes, click Unlock.

    To confirm unlocking* click OK and sign the transaction in your wallet.

    3.1. If you want to unlock the EYWA DAO NFT that is/was involved in voting, you need to cancel the votes. To cancel the votes, click Unfreeze and confirm the vote cancellation in the modal window.

    Alternatively, clicking Unlock will bring up a modal window displaying the lock contents and a prompt to unfreeze the EYWA DAO NFT to access its contents.

    To unfreeze the selected EYWA DAO NFT, click Unfreeze to unlock. The You’ll get field will show the number of unlocked EYWA tokens, vesting safes, and NFTs.

    To confirm the vote cancellation in the current/previous voting rounds, click Reset votes and sign the transaction in your wallet.

    After confirming the transaction on-chain, the EYWA DAO NFT will become available for unlocking.

    3.2. If you want to unlock an EYWA DAO NFT that has a timer set after detaching an NFT, you must wait 4 hours (front-running protection) before it can be moved. Click Unlock to initiate the process.

    Once the timer expires, the EYWA DAO NFT will become available for transfer.

    eywa_: The address of the EYWA token used for distributing rewards.

  • campaignParameters_: Initial set of campaign parameters (amount, duration, schedule, etc.) used in distribution campaigns.

  • references.
  • Stores s_campaignParameters from input.

  • If the new balance (multiplied by 1 hour / EPOCH_DURATION) meets the rewardTokenMinAmounts(...) requirement of DISTRIBUTION_CREATOR, the contract approves DISTRIBUTION_CREATOR to spend its entire balance and initiates a campaign:

    • Sets m_campaignParameters.amount to the new gauge balance.

    • Sets startTimestamp = uint32(block.timestamp).

    • Sets duration = uint32(EPOCH_DURATION) (one week).

    • Calls createCampaign(...) on DISTRIBUTION_CREATOR.

  • Emits RewardNotified(amount_).

  • string

    Expected output amount in smallest token units

    amountOutWithoutSlippage

    string

    Output amount without slippage applied

    tokenInPrice

    number

    USD price of the input token

    tokenOutPrice

    number

    USD price of the output token

    priceImpact

    number

    Price impact as a percentage

    sourceFee

    object

    Fee charged on the source chain

    deliveryFee

    object

    Fee for cross-chain delivery

    slippage

    number

    Slippage tolerance as provided in the request

    expectedFinalitySeconds

    number

    Estimated time to finality in seconds

    deadline

    number

    Expiration timestamp in milliseconds

    signature

    string

    Encrypted signature (pass to /tx/create as-is)

    txs

    array

    Per-chain gas estimates

    usd

    number

    Fee value in USD

    gasFeeUsd

    number

    Gas cost in USD

    gasFeeNative

    string

    Gas cost in the chain's native token

    params.tokenIn

    object

    Input token (address, symbol, decimals)

    params.tokenOut

    object

    Output token (address, symbol, decimals)

    params.amountIn

    string

    Input amount for this step

    params.amountOut

    string

    Output amount for this step

    0xde6724F8E4Ce4698c0096c58554e44F8aCE28600

    BNB Smart Chain (BSC) Testnet

    0xC07642337453820d51Bc60D7f39A53B202E691b8

    0xFA36e2B52b8a21347eB6c46401b210D547e7a4cA

    Sonic Testnet

    0x1992D29b2251F85A3f46B9da95b3A9DdD31CaED1

    0x3619F7DA7e8Cc2A6E264d351d2D9a2CD36894063

    0xE98Fd4eF563dCDfC535755f1FBCC0942a8e63517
    0xAB2f5D5A675F9004FEfcA7DC462e3C919a03E892
    0x962EDA2C1b103539cC13eF28951274d21291BC68

    legendary

    250 000

    infinity

    1 500 000

    rare

    9

    1 legendary

    legendary

    n/a

    n/a

    infinity

    n/a

    n/a

    1.036

    rare

    25 000

    1.3

    legendary

    250 000

    2.8

    infinity

    1 500 000

    3

    here
    Summation of veEYWA: The total amount of a user’s veEYWA is equal to the sum of the veEYWA of all their EYWA DAO NFTs.
    Detaching EYWA NFTs:
    • If an EYWA DAO NFT did not participate in pool voting in the current epoch:

      • EYWA NFTs can be attached at any time.

    • If an EYWA DAO NFT participated in pool voting in the current epoch:

      • The attached EYWA NFTs involved in voting cannot be detached

      • To detach them, you must cancel the vote for the pools.

  • Rare

    1,3

    25 000

    Legendary

    2,8

    250 000

    Infinity

    3

    1 500 000

    =*250000
  • If is less than or equal to , then: =+ *2.8;

  • Else: = + ; =-

  • =*25000

  • If is less than or equal to , then =+ *1.3;

  • Else: = + ; =-

  • =n*3000

  • If is less than or equal to , then =+ *1.036;

  • Else: = + ; =-

  • =*500

  • The overall results are equal to =+ *1.006

  • G=T156G=\frac{T}{156}G=156T​
    Tlockoutend=Tnow+Tendcurrentepoch+n∗Tepoch+24hourT_{lockout end} = T_{now} + T_{end current epoch} + n * T_{epoch} + 24 hourTlockoutend​=Tnow​+Tendcurrentepoch​+n∗Tepoch​+24hour
    G=156∗7∗24∗60−1156∗7∗24∗60G = \frac{156*7*24*60-1}{156*7*24*60}G=156∗7∗24∗60156∗7∗24∗60−1​
    G=156∗7∗24∗60−61156∗7∗24∗60G = \frac{156*7*24*60-61}{156*7*24*60}G=156∗7∗24∗60156∗7∗24∗60−61​
    VveEYWA=∑i=1nVi∗GiV_{veEYWA} = \sum^n_{i=1}V_{i}*G_{i}VveEYWA​=i=1∑n​Vi​∗Gi​

    Common

    1,006

    500

    Uncommon

    1,036

    Vrarity=Ncommon∗500+Nuncommon∗3000+Nrare∗25000+Nlegendary∗250000+Ninfinity∗1500000V_{rarity} = N_{common}*500+N_{uncommon}*3000+N_{rare}*25000+N_{legendary}*250000+N_{infinity}*1500000Vrarity​=Ncommon​∗500+Nuncommon​∗3000+Nrare​∗25000+Nlegendary​∗250000+Ninfinity​∗1500000
    Vresult=Vall−Vrarity+Ncommon∗500∗1.006+Nuncommon∗3000∗1.036++Nrare∗25000∗1.3+Nlegendary∗250000∗2.8+Ninfinity∗1500000∗3V_{result} = V_{all}-V_{rarity}+N_{common}*500*1.006+ N_{uncommon}*3000*1.036+ +N_{rare}*25000*1.3+N_{legendary}*250000*2.8+N_{infinity}*1500000*3Vresult​=Vall​−Vrarity​+Ncommon​∗500∗1.006+Nuncommon​∗3000∗1.036++Nrare​∗25000∗1.3+Nlegendary​∗250000∗2.8+Ninfinity​∗1500000∗3
    Vtemp=VallV_{temp} = V_{all}Vtemp​=Vall​

    The formula for the linear relationship between lock time and voting power boost is:

    Features of setting lock time in a smart contract when creating a lock

    The total votes a token holder has are calculated using the formula:

    EYWA DAO NFT

    Creating an EYWA DAO NFT

    Calculating veEYWA:

    Restrictions when creating an EYWA DAO NFT

    Modifying an EYWA DAO NFT

    Increasing veEYWA using EYWA NFTs

    NFT Rarity Types and Their Characteristics

    Calculating the NFT Boost to Increase Voting Power

    Examples of NFT Boost Calculations

    Maximum Possible Number of Votes

    Protection Against Front-Running Front-running is a practice in which someone (usually a trader or bot) gains information about an upcoming transaction and uses it to execute a trade earlier, thereby gaining an advantage.

    Locker
    Locker
    Locker
    EYWA Locker
    Locker
    Locker
    Locker

    3 000

    Select your EYWA NFTs and boost voting power - an option to select EYWA NFTs for the new lock, adding EYWA tokens from the NFT container and increasing the total veEYWA amount. It also grants a voting power boost based on the rarity of the EYWA NFT.

  • Lock time - selection of the locking duration.

  • Unlock time - the next lock expiration date
  • veEYWA - the voting power amount in veEYWA tokens for the selected lock

  • Staking APY - the APY yield for locked EYWA tokens (more details on staking APY here)

  • Transferable - the status of the selected NFT’s transferability*

  • Staking rewards - the amount of rewards received in EYWA tokens for the past lock period

  • EYWA DAO NFT is currently or was previously involved in voting during an epoch. In this case, to remove the frozen status, you need to cancel the vote by clicking Unfreeze
  • If an EYWA NFT was detached from an EYWA DAO NFT, a timer will be displayed showing the time remaining until the freeze is lifted, after which the EYWA DAO NFT can be moved. This is one of the front-running protection mechanisms.

  • Vesting ends in - the vesting expiration time
  • Total in lock - the total number of vesting safes in the lock and the total amount if EYWA tokens in them.

  • * Note: Creating a lock requires signing multiple transactions, as indicated on the Create Token Lock. For example: if you selected n EYWA tokens from your wallet balance, three vesting safes, and two EYWA NFTs, the total number of transactions to sign will be 5.

    1. Creating a lock with EYWA Tokens from your wallet

    The maximum lock duration is 3 years (156 weeks), ensuring the highest ratio: 1 locked token = 1 vote. The minimum lock duration is a few days (until the end of the current epoch), for example, 2 days provide 2/1092 votes.

    2. Selecting vesting safes for a new lock

    * Adding any type of vesting safes to a lock is only possible when creating a new lock. For an already created lock, it is possible to add vesting safes attached to an EYWA NFT.

    3. Boosting voting power by locking EYWA NFT.

    * Attention! In some cases, EYWA NFT may be unavailable for adding to the lock:

    Locker

    * There are two states of lock transferability:

    For example, if you have 1,000,000 EYWA tokens and one Legendary EYWA NFT with a container capacity of 250,000 tokens, then Unboosted tokens = 750,000, since tokens exceeding the container size are not included in the boost calculation

    * If the EYWA DAO NFT you selected for unlocking participated in voting, it is in Freeze status, and you need to cancel votes by clicking Unfreeze to withdraw

    * Unlocking after the lock period allows managing vesting safes in the Locker.

    lock formula section
    here
    Locker
    lock duration
    lock duration
    lock duration
    here
    here
    here
    tofunft
    opensea
    detach
    link
    lock duration
    here
    https://app.crosscurve.fi/locker
    here
    tofunft
    opensea
    here
    tofunft
    opensea

    Error Handling and Recovery

    Code
    Meaning

    429

    Rate limit exceeded

    500

    Internal server error

    All errors return a JSON object with an error field containing a message:

    For application-level errors (e.g. PusherError), the response also includes a code field:

    When a cross-chain transaction gets stuck, these endpoints help resolve the situation.

    POST /tx/create/emergency

    Build a transaction to return funds to the sender when delivery is stuck (destination.emergency is true).

    Field
    Type
    Description

    requestId

    string

    The request ID from the ComplexOpProcessed event

    signature

    string

    EIP-191 signature from the original sender (see below)

    Generating the signature:

    The server expects an EIP-191 personal sign over the keccak256 hash of the requestId string. The signer must be the original sender address.

    Full example:

    POST /tx/create/retry

    Retry a failed delivery. Uses the same signature format as the emergency endpoint.

    Field
    Type
    Description

    requestId

    string

    The request ID from the ComplexOpProcessed event

    signature

    string

    EIP-191 signature from the original sender

    POST /tx/create/resumeBr

    Resume a paused bridge relay.

    POST /tx/create/cancelBr

    Cancel a pending bridge relay.

    400

    Invalid request parameters

    403

    Invalid or missing api-key

    404

    HTTP Status Codes

    Resource not found

    Error Response Format

    Recovery Endpoints

    {
      "error": {
        "message": "description of the error"
      }
    }
    {
      "error": {
        "code": "NOT_SMART_ACCOUNT",
        "message": "Address has no deployed code — not a smart account"
      }
    }
    // Using ethers.js
    import { solidityPackedKeccak256, getBytes } from "ethers";
    
    const messageHash = solidityPackedKeccak256(["string"], [requestId]);
    const signature = await signer.signMessage(getBytes(messageHash));
    // Using viem
    import { keccak256, encodePacked, toBytes } from "viem";
    
    const messageHash = keccak256(encodePacked(["string"], [requestId]));
    const signature = await walletClient.signMessage({
      message: { raw: toBytes(messageHash) },
    });
    // Check if emergency is available
    const status = await fetch(`${API}/transaction/${requestId}`).then((r) => r.json());
    if (!status.destination.emergency) {
      console.log("Emergency not yet available — wait at least 30 minutes");
    }
    
    // Generate signature
    const messageHash = solidityPackedKeccak256(["string"], [requestId]);
    const signature = await signer.signMessage(getBytes(messageHash));
    
    // Build emergency transaction
    const res = await fetch(`${API}/tx/create/emergency`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ requestId, signature }),
    });
    const emergencyTx = await res.json();
    
    // Send on-chain
    await wallet.sendTransaction({
      to: emergencyTx.to,
      data: emergencyTx.data,
      value: emergencyTx.value,
    });
    const messageHash = solidityPackedKeccak256(["string"], [requestId]);
    const signature = await signer.signMessage(getBytes(messageHash));
    
    const res = await fetch(`${API}/tx/create/retry`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ requestId, signature }),
    });
    const retryTx = await res.json();
    // Send retryTx on-chain
    {
      "requestId": "0x..."
    }
    {
      "requestId": "0x..."
    }

    Leaderboard

    Leaderboard Section and Its Functionality

    The accrual of points for the Airdrop Season 2 ended at 24:00 UTC on 30 September 2025.

    To start working in the CrossCurve app, go to the Leaderboard section. There, click “Connect wallet” in the top right corner, choose a suitable wallet from the list, and confirm the connection, making sure you are on the original page https://app.crosscurve.fi/leaderboard.

    1. After successfully connecting, you will see complete statistics of your earned points for participation in the EYWA Adventure Quest Season 2. The page displays the total number of earned points (updated every 24 hours at 00 UTC), the points received for completing basic and bonus tasks, statistics of your referrals.

    Below, you will see the stats for your referrals, sorted by referral level and liquidity volume. It also shows your overall ranking, along with the number and volume of transactions. By switching between Season 1 (completed) and Season 2, you can see the stats for either of the seasons of the Airdrop.

    1. By following the link Season 2 airdrop activities, you can learn about activities that allow you to accumulate points for the EYWA Season 2 airdrop:

    • Swaps on DEX

      In this on-chain activity, you receive points for cross-chain swaps on our DEX, up to 250 points* per day. For completing a swap daily, you receive bonus points. Each new day starts at 00:00 UTC, with the points added within two hours of the transaction being verified on the blockchain

    • Early farming

      This new program rewards users for providing liquidity. Just lock your liquidity into the and pools and receive rEYWA (reward EYWA) tokens. rEYWA is a nontransferable ERC-20 token that you will be able to exchange 1:1 for EYWA after the TGE. Rewards accrue based on the Early Farming program rules and depend on the volume of liquidity provided and the pool chosen. rEYWA has a 90-day vesting period from the moment it’s claimed. Claiming is available at any time, but one must wait until the vesting period is complete in order to be able to exchange all of his rEYWA for EYWA 1:1. The exchange is only possible after the TGE (Token Generation Event). Exchanging rEYWA before the vesting is complete will give him EYWA for only the rEYWA that has already vested, with the rest being returned to the EYWA DAO treasury. Read the program’s details

    Introducing a new mechanic for accruing a reward for the daily completion of even one CrossCurve transaction. The new day starts at 00:00 UTC, and the points are accrued within two hours of the transaction’s confirmation on the blockchain.

    Reward table for daily task completion

    Consecutive days with at least one transaction
    Daily reward for Season 2 airdrop activity

    The daily limit of points one can receive for completing tasks is 250*. If a user had 240 points and completed a task worth 20 points, only 10 points will be accrued, equalling 250* in total. You can get points for two activity types:

    • Cross-chain swaps in the tab (up to 200 points/swap**)

    • Deposits into the liquidity pool on the Fantom network in the tab ( up to 250 points/swap***)

    You receive points for each cross-chain swap or LP in the tab.

    Transaction value *
    Base points **
    Bonus points**

    1. After entering the desired swap amount in the Swap tab, the app will reflect the number of points you will receive within two hours of the transaction confirmation on-chain. In the Daily Reward field, you’ll the number of points accrued for the daily completion of transactions.

    2. Clicking on info will give you complete information about your point accrual:

    • 70 base points for a swap of $1,000 to $4,999

    • 9,9 bonus points ( 3,3 for each $100 above $1,000)

    • Total amount of base points earned per day

    • Amount of points awaiting accrual within two hours

    1. To quickly find the optimal swap route go to the Find best route tab, and select token and network by clicking on Select Network and Token.

    After selecting token and network, enter the swap amount and click Find best route. The system will automatically find the best route for the swap.

    Points are rewarded for providing liquidity (Deposit) in in the tab. Points are also accrued for bridging* tokens from one chain to another.

    Single transaction value*
    Base points**
    Bonus points**

    After entering the desired deposit amount in the tab, the app will show you the number of points you’ll receive for this deposit, within two hours of the transaction confirmation on-chain.

    Through the referral system, you receive a part of the points from your referrals through our three-level program: 10% for the first level, 6% for the second level, and 4% for the third level. Points earned by each referral will be accrued once a day.

    By clicking “Get referral link”, you will need to log in through your X account.

    By clicking Connect Twitter, a new window will open for authorization through X. From there, click Authorize App.

    After successful authorization, you need to follow EYWA account on X by clicking Follow EYWA.

    Clicking Follow EYWA will open a new window to page. Click Follow.

    After following EYWA on Twitter, your referral for copying will appear.

    Clicking Post a Tweet and get Points will open a window to post the link in your account.

    To publish, click Post.

    EmissionManagerV1

    EmissionManagerV1

    Overview

    EmissionManagerV1 is an upgradeable contract that orchestrates weekly EYWA token emissions to various distribution streams, such as rebase rewards, gauge rewards, bonds, grants, and incentives. It integrates with the Escrow Manager to evaluate locked token balances and applies distinct emission formulas depending on whether the total locked tokens exceed a specified threshold. The contract also enforces constraints on weekly emissions, such as cooldown periods, maximum percentage increases, and valid distribution percentages.

    Key Features:

    • Epoch-Based Emissions: Emissions occur in discrete one-week epochs, with a configurable weekly emission amount.

    • Distribution Percentages: Tokens are split among rebase rewards, bonds, grants, and incentives, each receiving a percentage of the weekly emission.

    • Threshold-Based Adjustments: If total locked tokens exceed a s_lockThreshold, alternate base rates and multipliers are applied to rebase calculations.

    • Inflation Rates: Two inflation rates (s_initialInflationRate and s_secondaryInflationRate) further influence the rebase portion of weekly emissions.

    • Owner-Only Updates: Certain parameters, such as weekly emission amounts and distribution logic, can only be updated by the contract owner, subject to cooldowns and other constraints.

    By implementing the IEmissionManagerV1 interface, EmissionManagerV1 provides a clear set of functionalities and events essential for managing the emission process in the CrossCurve ecosystem.


    • UUPSUpgradeable (OpenZeppelin): Enables the contract to be upgradeable via a UUPS proxy pattern, ensuring only the owner can perform upgrades.

    • OwnableUpgradeable (OpenZeppelin): Provides ownership functionality, restricting sensitive actions (like parameter updates) to the owner.

    • IEmissionManagerV1: Interface declaring all essential methods (e.g., initialize, updateEpoch

    Additional External References:

    • SafeERC20, IERC20 (OpenZeppelin): Used for secure ERC20 operations.

    • IEscrowVoteManagerV1: Receives gauge emission amounts and coordinates gauge reward distribution.

    • IEscrowManager: Provides total locked token data for rebase emission calculations.


    • EPOCH_DURATION: Duration of each emission epoch (1 week).

    • TOTAL_SUPPLY: Total EYWA token supply (1 billion).

    • MAXIMUM_EMISSION_INCREASE_PERCENTAGE: Maximum allowed percentage by which the weekly emission can increase, scaled by PRECISION.


    • s_currentWeeklyEmission (uint256): Current weekly emission amount in EYWA tokens.

    • s_totalDistributedEmission (uint256): Accumulated amount of EYWA tokens distributed across all epochs.

    • s_gaugeEmissionPercentage (uint256): Percent of weekly emission allocated to gauge rewards, scaled by PRECISION.

    • s_bondEmissionPercentage (uint256): Percent allocated to bond rewards, scaled by PRECISION.

    • s_lockThreshold (uint256): The threshold of total locked tokens determining which emission formula to apply.

    • s_baseRateBelowThreshold (uint256): Base rate for rebase emission if locked tokens < s_lockThreshold.

    • s_baseRateAboveThreshold (uint256)

    • s_initialInflationRate (uint256): Inflation rate applied when locked tokens are below threshold.

    • s_secondaryInflationRate (uint256): Inflation rate used when locked tokens are above threshold.

    • s_currentEpochStart (uint256): Timestamp marking the start of the current emission epoch.

    • s_lastChangeEpochStart (uint256): Timestamp marking the start of the epoch during the last emission state change (used for cooldown enforcement).

    • s_epochCounter (uint256): Number of completed epochs.

    • s_treasury (address): Address holding the EYWA tokens (treasury).

    • s_rebaseRewardsDistributor (address): Distributor for rebase rewards.

    • s_bondEmissionDistributor (address): Distributor for bond emissions.


    • Description: Disables contract initializers to prevent re-initialization in a UUPS proxy context.


    Description: Initializes the contract for the first time, setting the owner, treasury, emission distributors, and references to external managers/tokens. Configures initial weekly emission, distribution percentages, threshold-based rates, and inflation rates.

    Parameters:

    • owner_: Contract owner address.

    • treasury_: Address of treasury holding EYWA tokens.

    • rebaseRewardsDistributor_: Distributor contract for rebase rewards.

    Effects:

    • Calls __UUPSUpgradeable_init() and __Ownable_init(owner_).

    • Sets initial values for emission rates, thresholds, and inflation parameters.

    • Marks the start of the current epoch.


    Description: Updates the treasury address from which emissions are withdrawn.

    Events:

    • Emits TreasuryUpdated(newTreasury_).


    Description: Updates the addresses for bond, grant, and incentive emission distributors. Only callable by the owner.

    Parameters:

    • newBondEmissionDistributor_: New bond emission distributor address.

    • newGrantEmissionDistributor_: New grant emission distributor address.

    • newIncentiveEmissionDistributor_: New incentive emission distributor address.

    Events:

    • Emits EmissionDistributorsUpdated.


    Description: Adjusts the weekly emission amount and distribution percentages. Enforces a cooldown (EPOCH_COOLDOWN_PERIOD) since the last change and forbids increases above the allowed percentage limit.

    Checks & Constraints:

    • Must have at least 1 epoch (s_epochCounter > 0).

    • Enforces cooldown: block.timestamp must be ≥ s_lastChangeEpochStart + EPOCH_COOLDOWN_PERIOD * EPOCH_DURATION.

    • newWeeklyEmission_

    Events:

    • Emits WeeklyEmissionStateUpdated.


    Description: Updates threshold-based emission parameters, including base rates, rate multipliers, and inflation rates used in rebase calculations.

    Events:

    • Emits ParametersUpdated with the updated values.


    Description: If a new epoch has started (block.timestamp >= s_currentEpochStart + EPOCH_DURATION), the contract calculates distributions for the new week and transfers tokens to the various distributors.

    Logic:

    1. Withdraws s_currentWeeklyEmission from s_treasury.

    2. Calculates rebase emission portion with _calculateRebaseEmission.

    3. Sends rebase emission to the rebase rewards distributor and calls checkpoint()

    Events:

    • Emits EpochUpdated with detailed breakdown.


    Description: Returns the average weekly emission across all completed epochs: s_totalDistributedEmission / s_epochCounter.


    • Description: Restricts the UUPS upgrade function to the contract owner.


    Description: Derives the rebase portion of the weekly emission based on total locked tokens from s_escrowManager.

    • If m_totalLocked >= s_lockThreshold, uses one set of base rates, multipliers, and s_secondaryInflationRate.

    • Otherwise, uses another set and s_initialInflationRate.

    Return:

    • rebaseEmission_: The final rebase token amount.

    Formula Components:

    1. Computes an adjustment factor that depends on s_baseRateAboveThreshold/s_rateMultiplierAboveThreshold or s_baseRateBelowThreshold/s_rateMultiplierBelowThreshold.

    2. Adds an inflation portion scaled by either s_secondaryInflationRate or s_initialInflationRate.


    • TreasuryUpdated(address newTreasury)

    • EmissionDistributorsUpdated(address newBondEmissionDistributor, address newGrantEmissionDistributor, address newIncentiveEmissionDistributor)

    • WeeklyEmissionStateUpdated(uint256 newWeeklyEmission, uint256 newGaugeEmissionPercentage, ..., uint256 newIncentiveEmissionPercentage)

    These events log critical changes such as treasury updates, changes to emission distribution, parameter updates, and epoch transitions.


    • InvalidCallee(): Thrown if an unauthorized entity calls certain functions (not used in current logic).

    • ZeroEpochCounter(): Thrown if updateWeeklyEmissionState is called before any epoch has elapsed.


    EmissionManagerV1 is a flexible and upgradeable contract for distributing EYWA tokens weekly to different reward mechanisms—governed by configurable rates and distribution percentages. By leveraging a threshold-based logic, it dynamically adjusts rebase emissions based on the total locked tokens, ensuring that ecosystem participation and inflation rates are balanced. It integrates seamlessly with treasury, escrow, and reward distributor contracts to enforce cooldowns, respect maximum emission growth, and emit relevant events detailing emission updates.

    ) and events for managing emissions.
    ITreasury: Manages treasury funds from which weekly emissions are withdrawn.
  • IRebaseRewardsDistributorV1: Distributes rebase rewards and triggers relevant accounting updates.

  • PRECISION: Scaling factor for percentage calculations (e.g., 100,000 means 100%).

  • EPOCH_COOLDOWN_PERIOD: Number of epochs required between emission state changes.

  • s_grantEmissionPercentage (uint256): Percent allocated to grants, scaled by PRECISION.
  • s_incentiveEmissionPercentage (uint256): Percent allocated to incentives, scaled by PRECISION.

  • : Base rate if locked tokens ≥
    s_lockThreshold
    .
  • s_rateMultiplierBelowThreshold (uint256): Rate multiplier if locked tokens < s_lockThreshold.

  • s_rateMultiplierAboveThreshold (uint256): Rate multiplier if locked tokens ≥ s_lockThreshold.

  • s_grantEmissionDistributor (address): Distributor for grant emissions.

  • s_incentiveEmissionDistributor (address): Distributor for incentive emissions.

  • s_escrowVoteManager (IEscrowVoteManagerV1): Escrow vote manager contract for gauge emissions.

  • s_escrowManager (IEscrowManager): Escrow manager providing locked token data.

  • s_eywa (IERC20): EYWA token used for emission distributions.

  • bondEmissionDistributor_: Distributor contract for bond rewards.

  • grantEmissionDistributor_: Distributor contract for grants.

  • incentiveEmissionDistributor_: Distributor contract for incentives.

  • escrowVoteManager_: The escrow vote manager contract instance.

  • escrowManager_: Escrow manager contract instance for locked token data.

  • eywa_: EYWA token contract.

  • must not exceed historical average times
    MAXIMUM_EMISSION_INCREASE_PERCENTAGE / PRECISION
    .
  • Sum of new distribution percentages = PRECISION (100%).

  • .
  • Distributes leftover among gauge, bond, grant, and incentive streams proportionally.

  • Increments s_epochCounter and updates s_totalDistributedEmission.

  • Divides by 1e18 at the end to restore integer arithmetic precision.

  • ParametersUpdated(..., uint256 initialInflationRate, uint256 secondaryInflationRate)

  • EpochUpdated(uint256 epochStartTimestamp, uint256 totalEmission, uint256 rebaseEmission, ..., uint256 incentiveEmission)

  • CooldownPeriodNotElapsed()
    : Thrown if a new weekly emission state update is attempted within the cooldown period.
  • ExcessiveEmissionIncrease(): Thrown if the new weekly emission exceeds the allowed maximum over historical average.

  • InvalidPercentagesSum(): Thrown if the sum of new distribution percentages does not equal PRECISION (100%).

  • Inherited Contracts and Interfaces

    Constants

    State Variables

    Emission Parameters

    Distribution Percentages

    Threshold and Rates

    Inflation Rates

    Epoch Management

    Addresses

    Constructor

    External Functions

    initialize(...)

    updateTreasury(address newTreasury_)

    updateEmissionDistributors(...)

    updateWeeklyEmissionState(...)

    updateParameters(...)

    updateEpoch()

    averageWeeklyEmissionOverTime()

    Internal and Private Functions

    _authorizeUpgrade(address)

    _calculateRebaseEmission(uint256 currentWeeklyEmission_)

    Events

    Errors

    Summary

    uint256 public constant EPOCH_DURATION = 1 weeks;
    uint256 public constant TOTAL_SUPPLY = _000_000_000e18;
    uint256 public constant MAXIMUM_EMISSION_INCREASE_PERCENTAGE = 25_000;
    uint256 public constant PRECISION = 00_000;
    uint256 public constant EPOCH_COOLDOWN_PERIOD = 12;
    constructor() {
        _disableInitializers();
    }
    function initialize(
        address owner_,
        address treasury_,
        address rebaseRewardsDistributor_,
        address bondEmissionDistributor_,
        address grantEmissionDistributor_,
        address incentiveEmissionDistributor_,
        IEscrowVoteManagerV1 escrowVoteManager_,
        IEscrowManager escrowManager_,
        IERC20 eywa_
    ) external initializer
    function updateTreasury(address newTreasury_) external onlyOwner
    function updateEmissionDistributors(
        address newBondEmissionDistributor_,
        address newGrantEmissionDistributor_,
        address newIncentiveEmissionDistributor_
    ) external onlyOwner
    function updateWeeklyEmissionState(
        uint256 newWeeklyEmission_,
        uint256 newGaugeEmissionPercentage_,
        uint256 newBondEmissionPercentage_,
        uint256 newGrantEmissionPercentage_,
        uint256 newIncentiveEmissionPercentage_
    ) external onlyOwner
    function updateParameters(
        uint256 lockThreshold_,
        uint256 baseRateBelowThreshold_,
        uint256 rateMultiplierBelowThreshold_,
        uint256 baseRateAboveThreshold_,
        uint256 rateMultiplierAboveThreshold_,
        uint256 initialInflationRate_,
        uint256 secondaryInflationRate_
    ) external onlyOwner
    function updateEpoch() external
    function averageWeeklyEmissionOverTime() external view returns (uint256)
    function _authorizeUpgrade(address) internal override onlyOwner
    function _calculateRebaseEmission(uint256 currentWeeklyEmission_) private view returns (uint256)

    Llamaville Mini App

    Your activity in the Llamaville app allows you to farm cryptodollars and receive new social and on-chain activity tasks as part of the 2nd season of our Airdrop program. Llamaville is a complete educational app. It immerses users into the world of crypto, allowing them to go through all the stages of growth, from fear and greed to success — without risking any real losses. The app is accessible only by invite, which you can request in EYWA’s official Telegram and Discord communities

  • Referral activity

    The 3-level referral program allows you to receive points for the activity of your friends. Generate your personal referral link by clicking Get your Referral link and invite others to join the program. You will instantly get a portion of the points as they earn them: 10% for level 1 referrals, 6% for level 2, and 4% for level 3. You can find more details about this program below.

  • 4

    40

    5

    60

    6

    80

    7

    100

    $100 to $999

    25 points

    0.5 points for each $10 above $100

    $1,000 to $4,999

    70 points

    3.3 points for each $100 above $1000

    $5,000 and up

    200 points

    -

    $10,000 to $49,999

    55 points

    4,9 for each $1,000 above $10,000

    $50,000 and up

    250 points

    -

    1

    10

    2

    20

    3

    $5 to $49

    4.2 points

    0.33 points for each $5 above $5

    $50 to $99

    7 points

    $700 to $999

    7 points

    -

    $1,000 to $9,999

    10 points

    * from 12:30 UTC 18/06/2025 x3 points will be credited - up to 750 points per day

    You can also join the ambassador program by filling out the form at the Join link.

    Mechanics of point accrual for on-chain DEX task completion

    * from 12:30 UTC 18/06/2025 x3 points will be credited - up to 750 points per day

    ** from 12:30 UTC 18/06/2025 x3 points will be credited - up to 600 points/swap

    *** from 12:30 UTC 18/06/2025 x3 points will be credited - up to 750 points/swap

    1. Reward for cross-chain swaps

    * transaction amount is considered in USD$ equivalent

    ** from 12:30 UTC 18/06/2025 all points are multiplied by x3.

    NOTE: The best route can send you to a network where you don’t have gas tokens, which can limit your subsequent transactions in that chain. Please check this before beginning the swap.

    2. Bridging rewards

    Bridge is the mechanism of moving tokens between blockchains based on the mint-and-burn principle, where the token is blocked or “burned” on the origin chain and its equivalent is created (“minted") on the destination chain.

    * Each Deposit/Withdrawal transaction carries a fee of 0.005% from the tx value but no less than $0.02. Transaction amount is considered in USD$ equivalent

    ** from 12:30 UTC 18/06/2025 all points are multiplied by x3.

    3. Referral program rules

    xSTABLE
    xWETH
    here
    Trade
    Liquidity
    Trade
    CrossCurve pools
    Liquidity
    Liquidity
    EYWA's Twitter
    link

    30

    1.8 points for each $5 above $50

    0.5 for each $100 above the first $1,000

    Liquidity transfer from Fantom to Sonic

    CrossCurve liquidity pools are starting their migration from the Fantom network to the Sonic network (learn more here). In this step-by-step guide, we will explore how to transfer your liquidity safely and profitably.

    Please carefully read the entire list of required actions for transferring liquidity before starting the process.

    When migrating to Sonic, keep in mind that the architecture of the pools has changed — instead of 8-directional paired pools are now used. Therefore, before transferring liquidity, please decide which paired pools you will transfer your liquidity to and how you will do it:

    • You can simply withdraw liquidity from a pool with 8 tokens and distribute it across 8 corresponding paired pools.

    • Alternatively, you can divert all liquidity from the old 8-directional pool to a single paired pool or split it across several.

    It’s also important to understand that, unlike the previous architecture, paired pools now include not only the directional (synthetic) token but also a "universal" token (xfrxUSD for USD, xfrxETH for ETH, and scBTC for BTC assets). Thus, transferring liquidity will require both the destination token and the "local universal" token.

    There are numerous ways to transfer liquidity, and it’s impossible to describe every scenario, so we’ll outline the key general steps:

    1. Choose the pool to which liquidity will be transferred, such as xsArbitrum.

    2. Determine the amoun of each token needed. In the Arbitrum example, you’ll need 25% frxUSD tokens and 25% scUSD tokens to obtain 50% xfrxUSD and 50% sUSDC_arb (percentages are based on the total liquidity planned for transfer to the xsArbitrum pool).

    3. Obtain the synthetic token corresponding to this direction—in this case,

    If you provided liquidity to CrossCurve pools on the Farms tab in the Fantom network, you’ll need to follow these steps to transfer your funds from the Fantom network to the Sonic network:

    1. Unstake your position on the Farms page.

    2. Decide which pools your liquidity will be transferred to:

    • You can distribute liquidity across 8 directions.

    • You can choose one or several directions.

    1. Decide which method you’ll use to transfer liquidity:

      • In Easy Mode, directly swap LP tokens from the pool for the required tokens.

    Examples of swap directions in Easy Mode:

    • xSTABLE → sUSDT_eth

    • xSTABLE3 → sUSDC_arb

    • xSTABLE2 → sUSDC_ba

    Examples of swap directions in Balanced Mode:

    • s3CRV_e → sUSDT_eth

    • s2CRV_ar → sUSDC_arb

    • s4pool_b → sUSDC_ba

    1. Swap your FTM for S (or obtain S) to pay for gas (gwei).

    2. Obtain the universal token for paired pools:

    • For USD pools, obtain the LP token xfrxUSD.

    • For ETH pools, obtain the LP token xfrxETH.

    • For BTC pools, obtain the scBTC token.

    1. Obtain a synthetic token corresponding to the desired direction (e.g., sUSDT_eth, sUSDC_arb, sUSDC_ba, etc.)

    2. Deposit liquidity into the pools:

    • To obtain xfrxUSD, deposit frxUSD and scUSD into the pool.

    • To obtain xfrxETH, deposit frxETH and scETH into the pool.

    1. Lock liquidity in the new pools on the Sonic network to earn profits.

    Each paired pool in the Sonic hub-chain consists of two tokens:

    • A universal token—an asset from Sonic, common for all pools of the same type (xfrxUSD for USD assets, xfrxETH for ETH, and scBTC for BTC).

    • A synthetic derivative, backed by the original asset locked in the Consensus Bridge. This can be either a single asset or LP tokens from Curve.

    Universal tokens come in three types:

    • For USD pools: LP token xfrxUSD.

    • For ETH pools: LP token xfrxETH.

    • For BTC pools: scBTC token.

    To obtain xfrxUSD, follow these three steps:

    1. Obtain frxUSD on Sonic.

    2. Obtain scUSD on Sonic.

    3. Deposit frxUSD and scUSD into the CrossCurve frxUSD pool to receive xfrxUSD.

    You can obtain frxUSD and scUSD in various ways; below are a few methods.

    frxUSD tokens on the Fraxtal network can be swapped from any available asset in the app.

    Then, bridge them to the Sonic network on .

    In the app, you can transfer any available asset to the Ethereum network, receiving USDT, USDC, or DAI.

    Then, scUSD tokens can be swapped in the app by depositing the available assets as collateral.

    Choose your preferred app from the list of bridges in the section under Apps in the Bridge category.

    Swaps are also available on the aggregator for any available assets.

    To obtain the LP token xfrxUSD, you need to provide liquidity in the pool:.

    Go to the pool page and connect your wallet.

    Enter the desired deposit amount on the Deposit tab. To avoid losses due to slippage, it’s recommended to deposit funds in a balanced manner by clicking Add all coins in a balanced proportion (learn more ).

    In the first transaction, confirm the spending of funds by clicking Approve Spending and signing the transaction in your wallet.

    In the second transaction, deposit the funds by clicking Deposit and signing the transaction in your wallet.

    After the transaction is successfully confirmed on-chain, your wallet will display the amount of received xfrxUSD LP tokens.

    To obtain xfrxETH, follow these three steps:

    1. Obtain frxETH on Sonic.

    2. Obtain scETH on Sonic.

    3. Deposit frxETH and scETH into the CrossCurve frxETH pool to receive xfrxETH.

    You can obtain frxETH and scETH in various ways; below are a few methods.

    wfrxETH tokens on the Fraxtal network can be swapped from any available asset in the app.

    Then, bridge them to the Sonic network on .

    In the app, you can transfer any available asset to the Ethereum network, receiving WETH or ETH.

    Then, scETH tokens can be swapped in the app by depositing the available assets as collateral.

    Choose your preferred app from the list of bridges in the section under Apps in the Bridge category.

    Obtaining scETH or frxETH Using the Jumper.exchange aggregator

    Swaps are also available on the aggregator for any available assets.

    To obtain the LP token xfrxETH, you need to provide liquidity in the pool:.

    Go to the pool page and connect your wallet.

    Enter the desired deposit amount on the Deposit tab. To avoid losses due to slippage, it’s recommended to deposit funds in a balanced manner by clicking Add all coins in a balanced proportion (learn more ).

    In the first transaction, confirm the spending of funds by clicking Approve Spending and signing the transaction in your wallet.

    In the second transaction, deposit the funds by clicking Deposit and signing the transaction in your wallet.

    After the transaction is successfully confirmed on-chain, your wallet will display the amount of received xfrxETH LP tokens.

    You can obtain scBTC using the official Rings issuer app. Alternatively, you can use third-party services listed below.

    In the app, you can transfer any available asset to the Ethereum network, receiving WBTC.

    Then, scBTC tokens can be swapped in the app by depositing WBTC on the Ethereum network as collateral.

    Choose your preferred app from the list of bridges in the section under Apps in the Bridge category.

    Obtaining scBTC using the Jumper.exchange aggregator

    Swaps are also available on the aggregator for any available assets.

    Each paired pool on the Sonic hub-chain consists of two tokens:

    • A universal token – an asset from Sonic, uniform across all pools of the same type (e.g., xfrxUSD for USD assets, xfrxETH for ETH, and scBTC for BTC).

    • A synthetic derivative, backed by the original asset locked in the Consensus Bridge. These can be either single assets or LP tokens from Curve.

    sUSDC_arb tokens on the Sonic network can be swapped from any available asset in the xsArbitrum pool via the app.

    1. Navigate to the Liquidity tab in the Yield section. Select the Balanced mode and click Next.

    Enter the desired amount to swap, approve the spending by clicking Approve, and sign the transaction in your wallet.

    Click Swap to execute the exchange and confirm the transaction in your wallet.

    1. If you know the swap direction, you can also perform the exchange in the tab using any available asset.

    To provide liquidity to Sonic pools:

    • Select the pool where you want to transfer liquidity, e.g., xsArbitrum.

    • Determine the required token amounts.

    • Obtain the synthetic token for this direction, in this case, .

    • For USD pools, acquire tokens. For example, deposit an equal amount of and into the pool.

    • Deposit the universal token and the directional (synthetic) token into the paired pool.

    Navigate to the pool page: and connect your wallet.

    Enter the desired deposit amount in the Deposit tab. To avoid losses due to slippage, it’s recommended to deposit using the balanced method by clicking Add all coins in a balanced proportion (more details ).

    In the first transaction, approve the spending by clicking Approve Spending and sign the transaction in your wallet.

    In the second transaction, deposit the funds by clicking Deposit and sign the transaction in your wallet.

    After the transaction is confirmed on-chain, the amount of received xsArbitrum LP tokens will appear in your wallet.

    LP xsArbitrum tokens on the Sonic network can be swapped from any available asset in the xsArbitrum pool via the app.

    Go to the Liquidity tab in the Yield section. Select the Easy mode and click Next.

    Choose the available asset for the swap.

    Enter the desired amount to swap, approve the spending by clicking Approve, and sign the transaction in your wallet.

    Click Swap to execute the exchange and confirm the transaction in your wallet.

    To provide liquidity to CrossCurve pools navigate to the Farms page in the Yield section: and connect your wallet.

    In the xsArbitrum pool tab, click Stake LP and get rewards.

    Enter the deposit amount, approve the spending by clicking Approve, and sign the transaction in your wallet.

    After successful confirmation, deposit the funds by clicking Stake and sign the transaction in your wallet.

    The deposited amount will appear in the Staked field.

    You can view the current vAPR and accrued rewards in the selected pool by clicking on the APY icon.

    IncentiveRewardsDistributor

    Overview

    IncentiveRewardsDistributor is a contract that builds upon an abstract RewardsDistributor to manage the distribution of incentive rewards within the CrossCurve ecosystem. The RewardsDistributor base contract provides fundamental logic for tracking deposits, withdrawals, reward notifications, and reward claims over discrete epochs. The IncentiveRewardsDistributor adds:

    1. Whitelisting of Tokens: Before accepting a new token as a reward token, it checks with the escrow vote manager to ensure it is whitelisted.

    2. Escrow Vote Manager Authorization: Restricts calls to certain functions (like getReward) to only the authorized vote manager.

    3. Inheritance and Extended Logic: Integrates seamlessly with the epoch-based deposit/withdraw system in RewardsDistributor to finalize reward amounts and calculations.

    By implementing IIncentiveRewardsDistributor, this contract conforms to a standard reward distributor interface used throughout the CrossCurve ecosystem.


    • RewardsDistributor (Abstract Contract):

      • Manages core reward distribution functionality, such as:

        • Tracking how many tokens each owner has deposited during a specific epoch.

    Additional External References:

    • IEscrowVoteManagerV1:

      • Provides s_isWhitelistedToken to validate new reward tokens.

      • Acts as an authorization gate for methods that require msg.sender to be the vote manager.


    The base RewardsDistributor constructor sets immutable references for ESCROW_VOTE_MANAGER and ESCROW_MANAGER. It also defines the following main categories of functionality:

    1. Epoch-Based Deposit and Withdrawal:

      • deposit(uint256 amount_, uint256 tokenId_)

      • withdraw(uint256 amount_, uint256 tokenId_)

    We now detail each of these base functions.


    • Description: Sets ESCROW_VOTE_MANAGER and ESCROW_MANAGER as immutable addresses, used for authorization and lock ownership lookups.

    • Parameters:

      • escrowVoteManager_


    • Description:

      • Called by the escrow vote manager to record that amount_ of tokens have been deposited for the lock represented by tokenId_ in the current epoch.

      • Increments the total supply and the lock owner’s balance for the current epoch.


    • Description:

      • Called by the escrow vote manager to record that amount_ of tokens have been removed from the lock represented by tokenId_ in the current epoch.

      • Decrements the total supply and the lock owner’s balance for the current epoch.


    • Description: Returns the length of the s_rewardTokens array, i.e., how many reward tokens the distributor currently recognizes.

    • Return:

      • uint256: number of recognized reward tokens.


    • Description:

      • Computes how many tokens of rewardToken_ the owner_ has earned across epochs since their last claim.

      • Iterates through epochs in weekly increments up to a maximum of 52 (1-year look-back) or until reaching the current epoch.


    • Description:

      • Returns how many rewardToken_ tokens were earned by owner_ specifically in a single epoch.

      • Calculated as rewardPerToken(rewardToken_, epoch_) * s_balanceByOwnerAndEpoch[owner_][epoch_] / 1e18


    • Description:

      • Calculates the distribution ratio for rewardToken_ in a given epoch_.

      • If s_totalSupplyByEpoch[epoch_]


    • Description:

      • Abstract in the base RewardsDistributor. The child contract (IncentiveRewardsDistributor) provides the actual implementation.

      • Child’s implementation calls _getReward(...) internally after verifying authorization.


    • Description:

      • Abstract method for adding new reward tokens. Child contract overrides this to add whitelisting checks or additional logic.

      • The base logic is available in _notifyRewardAmount(...) (see below).


    • Description:

      • The internal function that loops over rewardTokens_, calculates earned(...), updates s_lastRewardClaimByOwnerAndToken, and transfers the reward to owner_.


    • Description:

      • Transfers rewardAmount_ of rewardToken_ from sender_ to this distributor.


    • Description:

      • Calls the RewardsDistributor constructor to set ESCROW_VOTE_MANAGER and ESCROW_MANAGER.

      • No additional logic besides inheritance.


    • Description:

      • Implementation of getReward from both RewardsDistributor (abstract) and IIncentiveRewardsDistributor.


    • Description:

      • Implementation of notifyRewardAmount from both RewardsDistributor (abstract) and IIncentiveRewardsDistributor.


    1. TokensDeposited(from, tokenId, amount)

    2. TokensWithdrawn(from, tokenId, amount)

    3. RewardNotified(from, token, epoch, amount)

    • InvalidRewardToken()

    • UnauthorizedAccess()

    • ZeroAmountProvided()

    No new custom events or errors are introduced in IncentiveRewardsDistributor beyond what’s inherited.


    IncentiveRewardsDistributor leverages the robust, epoch-based reward accounting system from RewardsDistributor to facilitate secure incentive distribution in the CrossCurve ecosystem, adding token whitelisting checks and limiting reward claims (getReward) to calls from the escrow vote manager. This design ensures:

    • Authorized Control: Only recognized and whitelisted tokens can be notified as rewards; only the escrow vote manager can trigger claims.

    • Accurate Reward Calculations: Inherits deposit/withdraw logic to track each user’s epoch-based balance.

    • Easy Integration: Conforms to the IIncentiveRewardsDistributor interface, providing consistent methods for reward notifications and claims across the system.

    Together with the RewardsDistributor base contract, IncentiveRewardsDistributor offers a flexible, robust means of awarding incentive tokens in a multi-lock, epoch-based environment.

    EscrowVoteManagerV1

    EscrowVoteManagerV1 is a governance-related contract that manages gauge creation, voting power distribution, reward claiming, and other functionalities within the CrossCurve ecosystem. It integrates with:

    • Escrow Manager (IEscrowManager): Tracks locked EYWA positions.

    • Emission Manager (IEmissionManagerV1): Supplies emission epochs and total reward amounts.

    Storing how many rewards are allocated to a token for each epoch.
  • Calculating earned rewards for each owner at specific epochs and enabling claim logic.

  • Declares and implements the IRewardsDistributor interface.

  • IIncentiveRewardsDistributor:

    • Extends IRewardsDistributor with additional constraints and methods (getReward & notifyRewardAmount restricted to certain checks).

  • IEscrowManager:

    • Gives ownership and deposit/withdraw data for NFT-based locks.

    • Indirectly leveraged via RewardsDistributor functions for deposit/withdraw logic.

  • ReentrancyGuard (OpenZeppelin):

    • Inherited in RewardsDistributor to prevent re-entrant calls.

  • SafeERC20, IERC20 (OpenZeppelin):

    • Used for secure ERC20 transfers.

  • Reward Notification and Calculation:

    • notifyRewardAmount(address rewardToken_, uint256 rewardAmount_) (abstract here, implemented in the child contract)

    • earned(address owner_, address rewardToken_) and earnedByEpoch(address owner_, address rewardToken_, uint256 epoch_)

    • rewardPerToken(address rewardToken_, uint256 epoch_)

  • Claiming Rewards:

    • getReward(address owner_, address[] calldata rewardTokens_) (abstract here, partially implemented in the child)

    • _getReward(address owner_, address[] calldata rewardTokens_) (internal)

  • Data Structures for Epoch Accounting and Balances:

    • Mappings storing how much each user has deposited per epoch, total supply per epoch, and how much reward is allocated per epoch.

  • : The address of the escrow vote manager contract.
  • escrowManager_: The address of the escrow manager contract.

  • Checks:

    • msg.sender == ESCROW_VOTE_MANAGER; otherwise UnauthorizedAccess().

  • Logic:

    1. Queries the current epoch start via IEscrowVoteManagerV1(ESCROW_VOTE_MANAGER).currentEpochStart().

    2. Increments s_totalSupplyByEpoch[m_currentEpochStart] by amount_.

    3. Retrieves lock owner via IEscrowManager(ESCROW_MANAGER).ownerOf(tokenId_).

    4. Increments s_balanceByOwnerAndEpoch[m_owner][m_currentEpochStart] by amount_.

    5. Emits TokensDeposited(m_owner, tokenId_, amount_).

  • Checks:

    • msg.sender == ESCROW_VOTE_MANAGER; otherwise UnauthorizedAccess().

  • Logic:

    1. Gets the current epoch start, as with deposit.

    2. Decrements s_totalSupplyByEpoch[m_currentEpochStart] by amount_.

    3. Finds lock owner and decreases s_balanceByOwnerAndEpoch[m_owner][m_currentEpochStart] by amount_.

    4. Emits TokensWithdrawn(m_owner, tokenId_, amount_).

  • Returns:

    • (uint256 m_reward, uint256 m_lastRewardClaim): the total reward due and the final epoch boundary used for calculation.

  • Logic:

    1. Checks if rewardToken_ is recognized in s_isRewardToken[rewardToken_]. If not, returns (0,0).

    2. Locates the last claimed epoch timestamp for (owner_, rewardToken_).

    3. Repeatedly calls earnedByEpoch(...) for each epoch from m_lastRewardClaim up to but not including currentEpochStart.

    4. Summation is the total pending rewards.

  • .
    is zero, it simply returns
    s_rewardAmountByTokenAndEpoch[rewardToken_][epoch_]
    .
  • Otherwise, divides that reward amount by the epoch’s total supply (scaled by 1e18).

  • Return:

    • uint256: The per-token reward ratio used to multiply by an owner’s deposit amount to get their share.

  • Finally, emits RewardsClaimed(owner_, token, amount).

    Adds the difference in the contract’s balance to
    s_rewardAmountByTokenAndEpoch[rewardToken_][currentEpochStart]
    .
  • If s_initialIncentiveTimestamp == 0, sets it to the current epoch start.

  • Emits RewardNotified(sender_, rewardToken_, epoch, difference).

  • Allows the escrow vote manager to claim rewards for owner_.
  • Calls _getReward(...) internally after checking msg.sender == ESCROW_VOTE_MANAGER.

  • First ensures rewardToken_ is whitelisted via s_isWhitelistedToken in IEscrowVoteManagerV1.
    • If the token is not recognized (!s_isRewardToken[rewardToken_]), checks the vote manager to see if it’s whitelisted; if so, it’s now added to s_rewardTokens.

    • If not whitelisted, reverts with NotWhitelisted().

  • Calls _notifyRewardAmount(msg.sender, rewardToken_, rewardAmount_) to handle actual fund transfer and epoch reward updates.

  • RewardsClaimed(from, token, amount)

    NotWhitelisted()

    Inherited Contracts and Interfaces

    Contract Architecture

    Inherited from RewardsDistributor

    Functions in the Base Contract: RewardsDistributor

    1. Constructor

    2. deposit(uint256 amount_, uint256 tokenId_)

    3. withdraw(uint256 amount_, uint256 tokenId_)

    4. getRewardTokensCount()

    5. earned(address owner_, address rewardToken_)

    6. earnedByEpoch(address owner_, address rewardToken_, uint256 epoch_)

    7. rewardPerToken(address rewardToken_, uint256 epoch_)

    8. getReward(address owner_, address[] calldata rewardTokens_) (abstract)

    9. notifyRewardAmount(address rewardToken_, uint256 rewardAmount_) (abstract)

    10. _getReward(address owner_, address[] calldata rewardTokens_) (internal)

    11. _notifyRewardAmount(address sender_, address rewardToken_, uint256 rewardAmount_) (internal)

    Functions in IncentiveRewardsDistributor

    Constructor

    getReward(address owner_, address[] calldata rewardTokens_)

    notifyRewardAmount(address rewardToken_, uint256 rewardAmount_)

    Events and Errors

    Inherited Events

    Inherited Errors

    Summary

    Rewards Distributor Factory (IRewardsDistributorFactoryV1): Deploys incentive reward distributor contracts for new gauges.
  • Gauge Factory (IGaugeFactoryV1): Deploys gauge contracts, which are used to distribute rewards based on votes.

  • Reward Distributors (IRewardsDistributor): Handle depositing and withdrawing of votes and distributing claimable incentives.

  • The contract also includes logic for:

    1. Voting with multiple token IDs: A user can cast votes across multiple locks (NFTs) for multiple pools.

    2. Transfer Freeze after Deboost: Adds a cooldown period preventing NFT transfers after a lock has been deboosted in the Escrow Manager.

    3. Gauge Lifecycle Management: Owners can create, kill, or revive gauges.

    4. Reward Distribution: Accumulates gauge rewards and distributes them after each epoch.

    By implementing IEscrowVoteManagerV1, EscrowVoteManagerV1 provides a standardized API for gauge-based governance interactions in the CrossCurve ecosystem.


    • UUPSUpgradeable (OpenZeppelin): Provides upgrade functionality under the UUPS proxy pattern, restricted to the contract owner.

    • OwnableUpgradeable (OpenZeppelin): Manages ownership, allowing only the owner to modify critical parameters and authorize upgrades.

    • IEscrowVoteManagerV1: Defines core methods (e.g., vote, createGauge, distributeRewardsForMultipleGauges) and events for this contract.

    Additional External References:

    • SafeERC20, IERC20 (OpenZeppelin): Handles secure ERC20 operations for distributing and approving token transfers.

    • Math (OpenZeppelin): Provides utility math functions, e.g., Math.max.

    • IEscrowManager: Holds locked token data and checks voting power and freeze logic.

    • IRewardsDistributorFactoryV1, IGaugeFactoryV1: Deploy new reward distributors and gauge contracts, respectively.

    • IGaugeV1: Interface for a gauge contract that can receive reward notifications (notifyRewardAmount).

    • IEmissionManagerV1: Informs about epoch starts and ensures updated weekly distributions.


    • EPOCH_DURATION: Duration of each emission/gauge epoch (1 week).

    • PRECISION: Scaling factor (1e18) for reward calculations and distribution indexes.


    • s_transferFreezeAfterDeboost (uint256) Duration (in seconds) that locks are non-transferable after a deboost in the Escrow Manager.

    • s_emissionManager (address) Address of the emission manager contract, which calls this manager to notify new rewards.

    • s_eywa (address) Address of the EYWA token used for gauge rewards.

    • s_escrowManager (IEscrowManager) Reference to the contract that manages locked tokens (NFT-based locks).

    • s_rewardsDistributorFactory (IRewardsDistributorFactoryV1) Creates new rewards distributor contracts for gauges.

    • s_gaugeFactory (IGaugeFactoryV1) Creates new gauge contracts.

    • _s_distributionIndex (uint256) A global distribution index used to compute new reward distribution shares after the emission manager notifies reward amounts.

    • s_pools (address[]) An array of pool addresses that have gauges.

    • s_gaugeByPool (mapping(address => address)) Maps a pool address to its gauge contract address.

    • s_poolByGauge (mapping(address => address)) Reverse map: gauge address to the corresponding pool address.

    • s_incentiveRewardsDistributorByGauge (mapping(address => address)) Tracks which incentive rewards distributor belongs to which gauge.

    • s_votesByEpochAndPool (mapping(uint256 => mapping(address => uint256))) Records how many votes each pool has received in a given epoch (keyed by epoch start timestamp).

    • s_claimableRewardsByGauge (mapping(address => uint256)) Shows how many EYWA tokens each gauge can claim, waiting to be distributed.

    • s_lastDistributionTimestampByGauge (mapping(address => uint256)) Timestamp of the most recent reward distribution for each gauge.

    • s_isGauge (mapping(address => bool)) Indicates if an address is recognized as a gauge.

    • s_isWhitelistedToken (mapping(address => bool)) Tracks which tokens are whitelisted for reward distributions and voting.

    • s_isActiveGauge (mapping(address => bool)) If true, the gauge is active and can receive new rewards.

    • s_usedVotesByTokenId (mapping(uint256 => uint256)) How many votes a lock (NFT) has allocated.

    • s_lastVotedTimestampByTokenId (mapping(uint256 => uint256)) Timestamp of the last time a token ID voted, used to reset or poke votes.

    • s_votedPoolsByTokenId (mapping(uint256 => address[])) List of pools each token ID is currently voting for.

    • s_totalVotesByEpoch (mapping(uint256 => uint256)) Cumulative votes across all pools in a given epoch.

    • s_votesByTokenIdAndPool (mapping(uint256 => mapping(address => uint256))) Number of votes allocated by a specific token ID to a particular pool.

    • _s_supplyDistributionIndex (mapping(address => uint256)) Per-gauge distribution index to track how much of the global distribution index the gauge has accounted for.


    • Description: Disables contract initializers to prevent re-initialization in a UUPS proxy context.


    Description: Configures ownership, references, and initial state:

    • Sets s_transferFreezeAfterDeboost to 4 hours initially.

    • References the emission manager, escrow manager, gauge/rewards distributor factories, and whitelists initial tokens.


    Description: Updates the freeze period (in seconds) that applies after a deboost in Escrow Manager. This restricts NFT transfers for transferFreezeAfterDeboost_ seconds.

    Events:

    • Emits TransferFreezeAfterDeboostUpdated(oldDuration, newDuration).


    Description: Creates a new gauge for a specified pool by:

    1. Deploying an incentive rewards distributor via s_rewardsDistributorFactory.

    2. Deploying a gauge contract via s_gaugeFactory.

    3. Tracking the new gauge and marking it as active.

    Checks:

    • Ensures the pool does not already have a gauge.

    Events:

    • Emits GaugeCreated(pool_, gauge, incentiveRewardsDistributor).


    Description: Deactivates a gauge so it stops receiving future rewards. Does not remove votes or claimable rewards; simply marks it inactive.

    Checks:

    • s_isActiveGauge[gauge_] must be true.

    Events:

    • Emits GaugeKilled(gauge_).


    Description: Reactivates a previously killed gauge, allowing it to receive rewards again.

    Checks:

    • s_isActiveGauge[gauge_] must be false.

    Events:

    • Emits GaugeRevived(gauge_).


    Description: Updates whether tokens are whitelisted for reward distribution. Only callable by the contract owner. Checks input array lengths.

    Events:

    • Emits WhitelistStatusUpdatedForTokens(operator, tokens_, statuses_).


    Description: Allows a user to cast votes for multiple token IDs across multiple pools. For each token ID:

    1. Authorizes caller via IEscrowManager.checkAuthorized.

    2. Validates array lengths for pools and weights.

    3. Performs _vote(...) to reset old votes, allocate new votes, and update vote counts.


    Description: Removes all existing votes for a given token ID, setting them to zero. The caller must be authorized. Updates the token’s last vote timestamp.


    Description: Recalculates (re-casts) votes for a token ID based on updated voting power without changing the vote distribution pattern. The function still calls _vote(...) internally using the same pools and weights previously allocated.


    Description: Claims incentives for the caller from multiple rewards distributors. Each distributor has a list of reward tokens. Forwards the call to IRewardsDistributor.getReward.


    Description: Only callable by s_emissionManager. Increments _s_distributionIndex by an amount proportional to rewardAmount_ / totalVotesInPreviousEpoch. If no votes or unauthorized call, reverts.

    Events:

    • Emits RewardNotified(rewardAmount_).


    Description: Triggers an epoch update in the emission manager, then calls _distributeRewards(...) for each gauge in gauges_.


    Description: Also triggers an emission manager epoch update, then iterates through s_pools[start_ ... end_] to distribute rewards to each gauge.


    Description: Returns the number of pools (and thus gauges) tracked in s_pools.


    Description: Returns the next epoch’s start time as s_currentEpochStart + EPOCH_DURATION from the emission manager.


    Description: Returns the current epoch’s start time from the emission manager.


    Description: Restricts contract upgrades to the owner.


    Description: Handles the actual voting steps for a single token ID:

    1. Calls _reset(...) to remove existing votes.

    2. Proportionally allocates votingPower_ across pools based on weights_.

    3. Updates s_votesByEpochAndPool, s_votesByTokenIdAndPool, and s_votedPoolsByTokenId.

    4. Deposits votes into the associated gauge’s incentive rewards distributor.

    5. Tracks total votes used by the token ID (s_usedVotesByTokenId).

    6. Informs escrow manager the token has voted.

    Events:

    • VoteCast on each pool voted for.


    Description: Clears existing votes for tokenId_ by:

    • Withdrawing votes from all previously voted pools (if the token voted in the current epoch).

    • Adjusting s_votesByEpochAndPool and s_votesByTokenIdAndPool.

    • Updating the total votes for the epoch.

    • Marking the token as not voted in the escrow manager.

    • Emitting VotesAbstained.


    Description: Distributes claimable EYWA tokens to a specified gauge. If the gauge is inactive, does nothing. Otherwise:

    1. Calls _updateRewardIndexForGauge(...).

    2. Notifies the gauge of claimable rewards via notifyRewardAmount.

    Events:

    • RewardsDistributed after successful distribution.


    Description: Calculates how many new tokens a gauge can claim using the global distribution index. If there were votes in the previous epoch (currentEpochStart_ - EPOCH_DURATION), the gauge's share of _s_distributionIndex is updated, and claimable rewards are added to s_claimableRewardsByGauge[gauge_].


    • TransferFreezeAfterDeboostUpdated(oldDuration, newDuration) Emitted when the freeze period is changed.

    • GaugeCreated(pool, gauge, incentiveRewardsDistributor) Emitted upon successful gauge creation.

    • GaugeKilled(gauge), GaugeRevived(gauge) Emitted when a gauge is deactivated or reactivated.

    • WhitelistStatusUpdatedForTokens(operator, tokens, statuses) Shows updated whitelist status for multiple tokens.

    • RewardNotified(rewardAmount) Occurs when the emission manager notifies a new reward sum.

    • VoteCast(voter, pool, tokenId, votes) Occurs for each pool a token ID votes for.

    • VotesAbstained(voter, pool, tokenId, votes) Occurs when votes are reset/removed for a given pool.

    • RewardsDistributed(distributor, gauge, rewardAmount) Shows distribution of accumulated rewards to a gauge.


    • GaugeDoesNotExist() Thrown if a user tries to vote for a gauge that is not known (no gauge for that pool).

    • GaugeAlreadyExists() Thrown when creating a gauge for a pool that already has one.

    • GaugeNotActive() Thrown if an action (like voting or distributing) is attempted on an inactive gauge.

    • GaugeAlreadyActive() Thrown if reactivating a gauge that is already active.

    • UnauthorizedAccess() Thrown if a non-authorized caller tries to vote or manage votes.

    • InvalidArrayLengths() Thrown if arrays for tokenIds_, pools_, or weights_ do not match in length.

    • ZeroEntry() Thrown if some operation results in zero (e.g., zero votes allocated to a pool).

    • AlreadyVoted() Not used in current logic, but defined in the interface.

    • ProtectedFunctionSelectorUsed() Not used here (relates to proposal manager).

    • InvalidSliceParameters() Not used here, pertains to slicing logic in other modules.


    EscrowVoteManagerV1 orchestrates multi-token, multi-pool voting within the CrossCurve ecosystem. By coordinating gauges, incentive reward distribution, epoch-based reward notifications from the emission manager, and freeze logic from the escrow manager, it ensures a secure, transparent mechanism for users to direct token emissions to liquidity pools and other incentive-based programs. With features like deboost freeze periods and gauge lifecycle control, the contract provides flexible governance and reward distribution for token holders.

    Overview

    Inherited Contracts and Interfaces

    Constants

    State Variables

    Constructor

    External Functions (Defined by IEscrowVoteManagerV1)

    initialize(...)

    updateTransferFreezeAfterDeboost(uint256 transferFreezeAfterDeboost_)

    createGauge(address pool_, IDistributionCreator.CampaignParameters calldata campaignParameters_)

    killGauge(address gauge_)

    reviveGauge(address gauge_)

    setWhitelistStatusForTokens(address[] calldata tokens_, bool[] calldata statuses_)

    vote(uint256[] calldata tokenIds_, address[][] calldata pools_, uint256[][] calldata weights_)

    reset(uint256 tokenId_)

    poke(uint256 tokenId_)

    claimIncentives(address[] calldata incentiveRewardsDistributors_, address[][] calldata rewardTokens_)

    notifyRewardAmount(uint256 rewardAmount_)

    distributeRewardsForMultipleGauges(address[] calldata gauges_)

    distributeRewardsForGaugesInRange(uint256 start_, uint256 end_)

    getPoolsCount()

    nextEpochStart()

    currentEpochStart()

    Internal and Private Functions

    _authorizeUpgrade(address)

    _vote(...)

    _reset(uint256 tokenId_)

    _distributeRewards(address gauge_, uint256 currentEpochStart_)

    _updateRewardIndexForGauge(address gauge_, uint256 currentEpochStart_)

    Events

    Errors

    Summary

    IncentiveRewardsDistributor (Concrete)
     └── RewardsDistributor (Abstract)
          └── IRewardsDistributor (Interface)
    constructor(address escrowVoteManager_, address escrowManager_) {
        ESCROW_VOTE_MANAGER = escrowVoteManager_;
        ESCROW_MANAGER = escrowManager_;
    }
    function deposit(uint256 amount_, uint256 tokenId_) external
    function withdraw(uint256 amount_, uint256 tokenId_) external
    function getRewardTokensCount() external view returns (uint256)
    function earned(address owner_, address rewardToken_) public view returns (uint256, uint256)
    function earnedByEpoch(address owner_, address rewardToken_, uint256 epoch_) public view returns (uint256)
    function rewardPerToken(address rewardToken_, uint256 epoch_) public view returns (uint256)
    function getReward(address owner_, address[] calldata rewardTokens_) external virtual;
    function notifyRewardAmount(address rewardToken_, uint256 rewardAmount_) external virtual;
    function _getReward(address owner_, address[] calldata rewardTokens_) internal
    function _notifyRewardAmount(address sender_, address rewardToken_, uint256 rewardAmount_) internal
    constructor(address escrowVoteManager_, address escrowManager_) 
        RewardsDistributor(escrowVoteManager_, escrowManager_)
    {}
    function getReward(
        address owner_, 
        address[] calldata rewardTokens_
    )
        external
        override (RewardsDistributor, IIncentiveRewardsDistributor)
        nonReentrant
    function notifyRewardAmount(
        address rewardToken_, 
        uint256 rewardAmount_
    )
        external
        override (RewardsDistributor, IIncentiveRewardsDistributor)
        nonReentrant
    uint256 public constant EPOCH_DURATION = 1 weeks;
    uint256 public constant PRECISION = 1e18;
    constructor() {
        _disableInitializers();
    }
    function initialize(
        address owner_,
        address emissionManager_,
        address eywa_,
        IEscrowManager escrowManager_,
        IRewardsDistributorFactoryV1 rewardsDistributorFactory_,
        IGaugeFactoryV1 gaugeFactory_,
        address[] calldata whitelistedTokens_
    ) external initializer
    function updateTransferFreezeAfterDeboost(uint256 transferFreezeAfterDeboost_) external onlyOwner
    function createGauge(
        address pool_,
        IDistributionCreator.CampaignParameters calldata campaignParameters_
    ) external onlyOwner
    function killGauge(address gauge_) external onlyOwner
    function reviveGauge(address gauge_) external onlyOwner
    function setWhitelistStatusForTokens(
        address[] calldata tokens_,
        bool[] calldata statuses_
    ) external onlyOwner
    function vote(
        uint256[] calldata tokenIds_,
        address[][] calldata pools_,
        uint256[][] calldata weights_
    ) external
    function reset(uint256 tokenId_) external
    function poke(uint256 tokenId_) external
    function claimIncentives(
        address[] calldata incentiveRewardsDistributors_, 
        address[][] calldata rewardTokens_
    ) external
    function notifyRewardAmount(uint256 rewardAmount_) external
    function distributeRewardsForMultipleGauges(address[] calldata gauges_) external
    function distributeRewardsForGaugesInRange(uint256 start_, uint256 end_) external
    function getPoolsCount() external view returns (uint256)
    function nextEpochStart() external view returns (uint256)
    function currentEpochStart() external view returns (uint256)
    function _authorizeUpgrade(address) internal override onlyOwner
    function _vote(
        uint256 tokenId_,
        uint256 votingPower_,
        address[] memory pools_,
        uint256[] memory weights_
    ) private
    function _reset(uint256 tokenId_) private
    function _distributeRewards(address gauge_, uint256 currentEpochStart_) private
    function _updateRewardIndexForGauge(address gauge_, uint256 currentEpochStart_) private
    sUSDC_arb
    .
  • For USD and ETH pools, you’ll need to obtain xfrxUSD or xfrxETH tokens, respectively. To do this, in Sonic, you need to acquire frxUSD, scUSD, frxETH, and scETH accordingly. For example, you’ll need equal amounts of frxUSD and scUSD to deposit into the CrossCurve frxUSD pool.

  • Deposit the universal token and the destination token (synthetic) into the paired pool. In our example, you’ll need to deposit xfrxUSD and sUSDC_arb into the CrossCurve Stable ARB pool.

    • In Balanced Mode, withdraw 8 synthetic tokens from the LP token and swap them directly.

    Learn more about the changes in pool architecture.

    Pool Hub-Chain Structure Update

    This update will also affect the structure of the pool hub-chain. The previous pool system used Curve stable pools with 8 assets, connected via liquidity provider (LP) tokens from one or more pools:

    V1 Pools (xSTABLE, xSTABLE2, xSTABLE3) consist of 8 synthetic derivatives backed by the original asset locked in LP tokens on Curve.

    CrossCurve MetaLayer introduces a fundamentally new approach—liquidity isolation, where each pool contains liquidity for only one direction:

    V2 Each paired pool in the hub-chain consists of two tokens:

    • A universal token—an asset from Sonic, common for all pools of the same type (xfrxUSD for USD assets, xfrxETH for ETH, and scBTC for BTC).

    • A synthetic derivative, backed by the original asset locked in the Consensus Bridge. This can be either a single asset or LP tokens from Curve.

    As a result, all xSTABLE pools will transform into 20+ paired pools. When transferring liquidity, it won’t be possible to do a one-to-one transfer, as paired pools require an additional "universal" pool token.

    Brief list of all actions for Liquidity Transfer

    Note: This may result in losses due to conversion and slippage. For low liquidity pools and large amounts, losses can be significant.

    This method is more labor-intensive but allows for the most cost-effective swaps and is better suited for large liquidity amounts.

    Important Note: Rewards distribution in CrossCurve pools on the Fantom network will end at the conclusion of the current epoch. Voting for these pools and reward distribution to DAO participants in these pools will be paused. Starting from the next epoch, voting for reward allocation in the new pools on the Sonic network will begin.

    Detailed description of Liquidity Transfer actions

    Unstake LP tokens from CrossCurve Pools on Fantom

    Go to the Farms staking page to view all available pools and the size of your positions in them.

    1. First, withdraw accumulated rewards by clicking Claim in all pools and signing the transaction in your wallet.

    1. After successfully claiming rewards from the pool, click Unstake to withdraw LP tokens from staking.

    1. In the modal window, to select the maximum number of LP tokens to withdraw, click MAX next to the token balance in your wallet, then click Unstake to withdraw your liquidity from the pool and receive LP tokens on the Fantom network.

    1. Sign the transaction in your wallet.

    Withdraw Liquidity from LP Tokens in the Pool

    After receiving LP tokens, there are two methods to withdraw your liquidity:

    • Easy Mode via CrossCurve into a single asset of your choice (may incur penalties due to slippage).

    • Balanced Mode on Curve into the assets composing the LP in the pool (the most cost-effective method).

    1. Easy Mode via CrossCurve

    To quickly withdraw liquidity using Easy Mode, go to the Liquidity page under the Yield tab.

    In the pool list, under Choose pool, select the pool where you provided liquidity and have LP tokens.

    Select the withdrawal mode Withdraw, operation type Easy Mode, and click Next to proceed.

    Choose the asset you want to swap your LP token for by opening the selection list.

    Enter the amount of LP tokens to swap or click MAX to select the entire balance from your wallet. Click Approve and confirm the LP token spending operation in your wallet.

    After confirming the spending operation, click Swap to perform the exchange and sign the transaction in your wallet.

    Wait for the transaction to be processed on-chain.

    1. Balanced Mode via Curve

    To withdraw liquidity in Balanced Mode, go to the page of the pool you’re interested in on the Curve app using the quick link.

    If you haven’t performed an unstake in the CrossCurve app, go to the Withdrawal/Claim menu under the Unstake tab. Enter the number of LP tokens to unstake, click Unstake, and sign the transaction in your wallet.

    After the transaction is successfully confirmed on-chain, you’ll see a notification: Unstake Complete.

    Claim the rewards on the Claim Rewards tab by clicking Claim and signing the transaction in your wallet.

    To withdraw liquidity, go to the Withdraw tab, enter the number of LP tokens, select Balanced mode, and click Withdraw. Sign the transaction in your wallet.

    After the transaction is successfully confirmed on-chain, you’ll see a notification: Withdraw Complete.

    Obtaining Universal tokens for paired pools

    Obtaining LP xfrxUSD

    Obtaining frxUSD on Sonic using CrossCurve and Frax bridge

    Obtaining scUSD on Sonic using CrossCurve and Rings app

    Obtaining frxUSD and scUSD using other bridges for Sonic

    Obtaining frxUSD and scUSD Using the Jumper.exchange Aggregator

    Obtaining xfrxUSD via the Curve App interface

    If your wallet doesn’t support automatic token addition, add it manually as a custom token with the contract address 0xf1232a1ab5661abdd6e02c6d8ac9940a23bb0b84 on the Sonic network.

    Obtaining LP xfrxETH

    Obtaining frxETH on Sonic using CrossCurve and Frax bridge

    Obtaining scETH on Sonic using CrossCurve and Rings app

    Obtaining scETH or frxETH on Sonic using other bridges for Sonic

    Obtaining xfrxETH via the Curve App Interface

    If your wallet doesn’t support automatic token addition, add it manually as a custom token with the contract address 0x346704605c72d9f5f9F02D651e5A3DccE6964F3d on the Sonic network.

    Obtaining scBTC

    Obtaining scBTC on Sonic using CrossCurve and Rings app

    Obtaining scBTC on Sonic using other bridges for Sonic

    Obtaining a Synthetic Derivative

    Synthetic tokens are categorized into three types:

    • s_Stable_chain, where Stable represents a USD asset variant, and chain is the network where the asset is used.

    • s_WETH_network, where WETH represents ETH backing, and chain is the network where the asset is used.

    • s_WBTC_network, where WBTC represents BTC backing, and chain is the network where the asset is used.

    Each type of synthetic token corresponds to a pool where it can be paired in an LP token:

    • xs_chain, where xs is a stable pool, and chain is the network where the asset is used.

    • xe_chain, where xe is a volatile pool, and chain is the network where the asset is used.

    • xb_chain, where xb is a volatile pool, and chain is the network where the asset is used.

    Obtaining sUSDC_arb

    Note: Some directions may experience high slippage!

    Providing Liquidity to pools on Sonic

    For the Arbitrum example, you need 25% frxUSD and 25% scUSD to obtain 50% xfrxUSD and 50% sUSDC_arb (percentages are based on the total liquidity you plan to transfer to the xsArbitrum pool).

    In our example, deposit xfrxUSD and sUSDC_arb into the CrossCurve Stable ARB pool.

    Obtaining LP xsArbitrum via Curve

    If your wallet doesn’t automatically add the token, manually add it as a custom token using the contract address 0x440bcab62d629ba60ca56b80e565636e0c404e60 on the Sonic network.

    Obtaining LP xsArbitrum via CrossCurve

    Depositing LP xsArbitrum into the CrossCurve Stable ARB Pool

    CrossCurve
    Frax.com
    CrossCurve
    Rings
    mySonic
    Jumper.exchange
    CrossCurve frxUSD
    https://curve.finance/dex/sonic/pools/factory-stable-ng-25/deposit/
    CrossCurve frxUSD
    here
    CrossCurve
    Frax.com
    CrossCurve
    Rings
    mySonic
    Jumper.exchange
    CrossCurve frxETH
    https://curve.finance/dex/sonic/pools/factory-stable-ng-26/deposit/
    CrossCurve frxETH
    here
    CrossCurve
    Rings
    mySonic
    Jumper.exchange
    CrossCurve
    Trade
    sUSDC_arb
    xfrxUSD
    frxUSD
    scUSD
    CrossCurve frxUSD
    CrossCurve Stable ARB
    https://curve.finance/dex/sonic/pools/factory-stable-ng-73/deposit/
    here
    CrossCurve
    https://app.crosscurve.fi/farm

    EscrowManager

    Overview

    EscrowManager is a smart contract that manages locked EYWA tokens, each represented by a unique ERC-721 NFT (sometimes referred to as a "veEYWA" token). Each lock NFT stores information about its locked token amount, unlock time, vesting wallets, and booster NFTs. The contract supports operations like depositing, boosting, extending, deboosting, and withdrawing locked tokens, while tracking voting power via time-based checkpoints and epochs. It integrates with an external vote manager contract for governance operations and a collection contract for booster NFTs.

    Key Features:

    1. Lock Creation & Management: Users can create locks by transferring EYWA tokens, vesting wallets, or tokens from an NFT collection. They can add more tokens, apply boosters, or extend the lock duration.

    2. Voting Power: Each lock corresponds to voting power that evolves over time. The contract records checkpoints of ownership and calculates voting weights using a dynamic rate-of-change approach.

    3. Booster Mechanism: Boosters from the collection can increase a lock’s "coverage," thus effectively increasing its lock amount for voting power calculations.

    4. Cooldown & Freeze Logic: After certain actions such as deboosting, token transfers may be temporarily frozen to prevent immediate re-deposit or locking manipulations.

    5. Delegation Checks: The contract can integrate with a delegation manager to move voting power between addresses.

    By implementing the IEscrowManager interface, the EscrowManager contract provides a consistent API for user and external contract interactions in the CrossCurve ecosystem.


    • ERC721Enumerable, ERC721 (OpenZeppelin): Provides standard ERC-721 NFT functionality with enumeration capabilities, enabling easy listing of all minted NFTs.

    • ERC721Holder (OpenZeppelin): Allows the contract to safely hold ERC-721 tokens (necessary when receiving booster NFTs).

    • ReentrancyGuard (OpenZeppelin): Mitigates re-entrant calls on state-changing functions.

    External Interfaces:

    • IEscrowManager: The interface implemented by this contract, defining locking and booster logic.

    • IEscrowVoteManagerV1: The vote manager that tracks epochs, triggers freeze logic, and notifies about gauge rewards.

    • ICollection, IWalletFactory, IVestingWallet: Components in the ecosystem for NFT boosters, creating/managing vesting wallets, and bridging custom data.


    • ATTACHMENTS_LIMIT = 100 Maximum number of attachments (vesting wallets or booster NFTs) allowed per lock.

    • EPOCH_DURATION = 1 weeks Governs epoch-based calculations for voting power and lock logic.

    Immutable Addresses:

    • ESCROW_VOTE_MANAGER (address): The escrow vote manager contract address.

    • DELEGATION_MANAGER (address): The delegation manager contract address.


    • s_nextTokenId (uint256) The next NFT token ID to be minted.

    • s_epoch (uint256) Tracks how many epochs have occurred, updated whenever lock states change significantly.

    • s_totalLocked (uint256)

    Lock and Booster Details:

    • _s_lockInfoByTokenId (mapping(uint256 => LockInfo)): Internal mapping of lock data.

    • s_pureLockAmountByTokenId, s_vestingWalletsLockAmountByTokenId: Track base token amounts and vesting wallet contributions.

    Checkpointing and Voting:

    • s_checkpointsNumberByAccount (mapping(address => uint32)): Number of checkpoints for each account.

    • s_checkpoints (mapping(address => mapping(uint32 => Checkpoint))): Account checkpoints listing owned lock NFTs at different times.

    Deboost and Freeze Logic:

    • s_lastDeboostTimestampByTokenId (mapping(uint256 => uint256)): Records the last time a token was deboosted, used to freeze subsequent transfers.


    • Description: Deploys the EscrowManager, sets immutable addresses for the escrow vote manager, delegation manager, EYWA token, collection, wallet factory, and metadata provider, and initializes the NFT name and symbol.


    Description: Creates a lock by transferring lockAmount_ of EYWA from the caller, locking it for lockDuration_ (rounded down to epoch boundaries). Mints an NFT for recipient_.


    Description: Creates a lock by transferring tokens from multiple vesting wallets owned by the caller, then mints an NFT lock. Each vesting wallet's beneficiary must match the caller.


    Description: Creates a lock using tokens associated with the given collection token IDs. Collects vesting wallets pinned to those NFTs, locks their balances, and automatically applies boosters via _modifyBoost.


    Description: Adds extra EYWA to an existing lock. Requires caller authorization (_checkAuthorized).


    Description: Adds EYWA to an existing lock on behalf of the owner, without caller checks.


    Description: Associates additional booster NFTs with a lock, increasing its coverage and potentially its voting power. Booster NFTs may also bring vesting wallets if pinned.


    Description: Removes booster NFTs from a lock. Verifies that the token hasn't voted in the current epoch. Records the block timestamp in s_lastDeboostTimestampByTokenId to freeze transfers for a defined period.


    Description: Withdraws the tokens from an expired lock, returning booster NFTs, transferring vesting wallets, and burning the lock NFT. The caller must be authorized.

    Events:

    • Emits LockWithdrawn(recipient, tokenId, value) upon completion.


    Description: Extends the lock duration to a new unlockTime. Must be strictly greater than the current one. Updates voting power.


    Description: Only callable by ESCROW_VOTE_MANAGER. Marks a token as having voted or not.


    Description: Only callable by ESCROW_VOTE_MANAGER. Records that a token has voted (or not) in the current epoch.


    Description: Called by DELEGATION_MANAGER to transfer voting power if delegated. Ensures the token exists.


    Description: Returns the lock’s current amount, unlock timestamp, and associated vesting wallets.


    Description: Reports how many seconds remain until a token can be transferred again after deboost. Returns 0 if the freeze period has elapsed.


    Description: Retrieves the checkpoint at index_ for account_, listing token ownership at that historical checkpoint.


    Description: Calculates an account’s total voting power at a previous timestamp_, summing the power of all tokens they held at that time.


    Description: Returns the total voting power across all locks at the current time.


    Description: Returns the total voting power at a specific timestamp_. Uses the VotingPowerHelper for historical calculations.


    Description: Computes a single token’s voting power at a past timestamp_, factoring in rate-of-change data.


    Description: Lists all booster NFT IDs currently enhancing the lock identified by tokenId_.


    Description: Checks if spender_ is permitted (owner, approved address, or operator) to manage the NFT for tokenId_.


    Description: Returns true if an NFT for tokenId_ has been minted (i.e., the lock exists).


    Signature:

    Description: Core logic for creating a new lock. Mints an NFT, stores lock info, and transfers tokens or vesting wallets if needed.


    Signature:

    Description: Adds more EYWA to a lock, updating voting power calculations.


    Signature:

    Description: Adds or removes booster NFTs to/from a lock. Adjusts coverage and recalculates voting power accordingly.


    Signature:

    Description: Recomputes and stores new voting power points whenever a lock’s amount or unlock time changes. Adjusts historical checkpoints and the global epoch.


    Signature:

    Description: Reassigns voting power from from_ to to_ if the NFT’s ownership changes. Creates or updates checkpoints for both addresses.


    Signature:

    Description: Clears all references and data for a withdrawn or burned lock, freeing storage.


    Signature:

    Description: Helper to find or create the index for a checkpoint at the current timestamp for a given account.


    Signature:

    Description: Calculates the final lock amount after factoring in booster NFT coverage and rarity-based multipliers. If coverage exceeds lock amount, the algorithm partial-applies boosters in descending rarity.


    Emitted When: A user withdraws tokens from an expired lock. The NFT is burned, and booster NFTs/vesting wallets are returned.


    • InvalidBeneficiary()

    • InvalidVestingWallet()

    • InvalidLockDuration()

    These errors ensure that contract rules regarding lock durations, amounts, boosters, freeze periods, and ownership checks are strictly enforced.


    EscrowManager provides a robust system for locking EYWA tokens in exchange for NFT-based positions (veEYWA). Each lock can combine direct token transfers, vesting wallets, and booster NFTs, forming dynamic voting power that evolves over time. Freeze periods after deboosts and careful checkpointing logic protect against immediate manipulations of lock amounts and ownership. Through a clear interface defined in IEscrowManager, external ecosystem components (e.g., delegation managers, vote managers, NFT collections) can seamlessly integrate with this locking mechanism to support governance, incentive distribution, and user engagement within the CrossCurve platform.

    SafeERC20, IERC20 (OpenZeppelin): Provides secure wrappers for ERC20 operations, ensuring safe token transfers.

    IMetadataProviderV1: Supplies metadata URIs for NFTs.

  • VotingPowerHelper (Library): Used to compute historical voting power and supply based on stored checkpoints and rate-of-change data.

  • MAXIMUM_LOCK_DURATION
    = 156 weeks
    Maximum allowed lock duration in seconds (approximately 3 years).
  • MAXIMUM_NUMBER_OF_DELEGATES = 1024 Maximum delegates that can be tracked for a single account’s checkpoints.

  • SIGNED_MAXIMUM_LOCK_DURATION = 156 weeks Signed integer equivalent for arithmetic purposes.

  • Rarity Multipliers and Capacities: Predefined numerators and capacity values for Common, Uncommon, Rare, Legendary, and Infinity NFT rarities.

  • PRECISION = 100,000 Scaling factor for multiplier-based calculations (e.g., coverage, booster effects).

  • EYWA (IERC20)
    :
    The EYWA token used in locking.
  • COLLECTION (ICollection): The collection contract supporting booster NFTs.

  • WALLET_FACTORY (IWalletFactory): Factory contract for validating vesting wallets.

  • METADATA_PROVIDER (IMetadataProviderV1): Supplies off-chain metadata for NFTs.

  • Total EYWA tokens locked across all positions.
    s_currentCoverageByTokenId
    :
    Booster coverage for each lock.
  • s_boostersByTokenId, s_boostersByTokenIdAndRarity: Maintain sets of booster NFT IDs by token ID and rarity.

  • s_ownershipChangeBlockNumberByTokenId (mapping(uint256 => uint256))
    :
    Block number of the last ownership change for each NFT (prevents double-voting in the same block).
  • s_rateOfChangeByUnlockTime (mapping(uint256 => int128)): Tracks changes in voting power at specific unlock times.

  • s_hasVotedByTokenId (mapping(uint256 => bool)): Whether a token has voted in the current epoch.

  • s_hasVotedByEpochAndTokenId (mapping(uint256 => mapping(uint256 => bool))): Tracks vote status for each token in each epoch.

  • s_votingPowerPointByEpoch (mapping(uint256 => VotingPowerPoint)): Stores aggregated voting power changes per epoch.

  • s_votingPowerPointByTokenIdAndEpoch (mapping(uint256 => VotingPowerPoint[1000000000])): Voting power data for each token ID across epochs.

  • InvalidLockAmount()

  • InvalidCollectionTokenId(uint256 tokenId)

  • InvalidArrayLength()

  • InvalidRarity()

  • NonExistentToken()

  • ExtendedUnlockTimeMustBeGreater()

  • AttachmentsLimitExceeded()

  • LockStillActive()

  • LockCurrentlyVoting()

  • MaximumNumberOfDelegatesExceeded()

  • BoostModificationAfterVoting()

  • UnauthorizedCaller()

  • TransferFrozenDueToDeboost()

  • Inherited Contracts and Interfaces

    Constants

    State Variables

    Constructor

    External Functions (Defined by IEscrowManager)

    createLock(uint256 lockAmount_, uint256 lockDuration_, address recipient_)

    createLock(uint256 lockDuration_, address recipient_, address[] calldata vestingWallets_)

    createLock(uint256 lockDuration_, address recipient_, uint256[] calldata collectionTokenIds_)

    deposit(uint256 tokenId_, uint256 lockAmount_)

    depositFor(uint256 tokenId_, uint256 lockAmount_)

    boost(uint256 tokenId_, uint256[] calldata collectionTokenIds_)

    deboost(uint256 tokenId_, uint256[] calldata collectionTokenIds_)

    withdraw(uint256 tokenId_)

    extend(uint256 tokenId_, uint256 lockDuration_)

    setVoteStatus(uint256 tokenId_, bool status_)

    registerTokenVote(uint256 tokenId_, bool status_)

    moveVotes(uint256 tokenId_, address from_, address to_)

    getLockInfoByTokenId(uint256 tokenId_)

    getRemainingFreezeTimeByTokenId(uint256 tokenId_)

    getCheckpoint(address account_, uint32 index_)

    getPastVotes(address account_, uint256 timestamp_)

    getTotalSupply()

    getPastTotalSupply(uint256 timestamp_)

    getPastVotesByTokenId(uint256 tokenId_, uint256 timestamp_)

    getBoostersByTokenId(uint256 tokenId_)

    checkAuthorized(address owner_, address spender_, uint256 tokenId_)

    exists(uint256 tokenId_)

    Internal and Private Functions

    _createLock(...)

    _deposit(...)

    _modifyBoost(...)

    _updateLock(...)

    _moveVotes(...)

    _clearStorage(...)

    _findCheckpoint(...)

    _calculateModifiedLockAmount(...)

    Events

    LockWithdrawn(address indexed recipient, uint256 indexed tokenId, uint256 indexed value)

    Errors

    Summary

    constructor(
        address escrowVoteManager_,
        address delegationManager_,
        IERC20 eywa_,
        ICollection collection_,
        IWalletFactory walletFactory_,
        IMetadataProviderV1 metadataProvider_
    ) 
        ERC721("EYWA DAO NFT", "veEYWA")
    {
        ...
    }
    function createLock(
        uint256 lockAmount_,
        uint256 lockDuration_,
        address recipient_
    ) 
        external 
        nonReentrant
    function createLock(
        uint256 lockDuration_,
        address recipient_,
        address[] calldata vestingWallets_
    ) 
        external 
        nonReentrant
    function createLock(
        uint256 lockDuration_,
        address recipient_,
        uint256[] calldata collectionTokenIds_
    )
        external 
        nonReentrant
    function deposit(uint256 tokenId_, uint256 lockAmount_) external nonReentrant
    function depositFor(uint256 tokenId_, uint256 lockAmount_) external nonReentrant
    function boost(uint256 tokenId_, uint256[] calldata collectionTokenIds_) external nonReentrant
    function deboost(uint256 tokenId_, uint256[] calldata collectionTokenIds_) external nonReentrant
    function withdraw(uint256 tokenId_) external nonReentrant
    function extend(uint256 tokenId_, uint256 lockDuration_) external nonReentrant
    function setVoteStatus(uint256 tokenId_, bool status_) external
    function registerTokenVote(uint256 tokenId_, bool status_) external
    function moveVotes(uint256 tokenId_, address from_, address to_) external
    function getLockInfoByTokenId(uint256 tokenId_) 
        external 
        view 
        returns (
            int128 lockAmount_,
            uint256 unlockTime_,
            address[] memory vestingWallets_
        )
    function getRemainingFreezeTimeByTokenId(uint256 tokenId_) external view returns (uint256)
    function getCheckpoint(address account_, uint32 index_) external view returns (Checkpoint memory)
    function getPastVotes(address account_, uint256 timestamp_) external view returns (uint256 votes_)
    function getTotalSupply() external view returns (uint256)
    function getPastTotalSupply(uint256 timestamp_) external view returns (uint256)
    function getPastVotesByTokenId(uint256 tokenId_, uint256 timestamp_) external view returns (uint256)
    function getBoostersByTokenId(uint256 tokenId_) external view returns (uint256[] memory boosters_)
    function checkAuthorized(address owner_, address spender_, uint256 tokenId_) external view returns (bool)
    function exists(uint256 tokenId_) external view returns (bool)
    function _createLock(
        uint256 lockAmount_,
        uint256 lockDuration_,
        address recipient_,
        address[] memory vestingWallets_,
        LockModificationType lockModificationType_
    ) private
    function _deposit(uint256 tokenId_, uint256 lockAmount_) private
    function _modifyBoost(
        uint256 tokenId_, 
        uint256[] memory collectionTokenIds_, 
        LockModificationType lockModificationType_
    ) private
    function _updateLock(
        uint256 tokenId_,
        LockInfo memory previousLockInfo_,
        LockInfo memory currentLockInfo_
    ) private
    function _moveVotes(uint256 tokenId_, address from_, address to_) private
    function _clearStorage(uint256 tokenId_) private
    function _findCheckpoint(address account_) private view returns (uint32)
    function _calculateModifiedLockAmount(
        uint256 tokenId_,
        uint256 coverage_,
        uint256 lockAmount_
    ) private view returns (uint256)

    EOA Swap example

    EOA Swap flow

    A standard wallet swap (MetaMask, WalletConnect, or any EOA signer) in six steps:

    1. Fetch supported networks and tokens

    2. Find a route

    3. Approve token spending (ERC-20 only)

    4. Send swap transaction

    5. Extract requestId from receipt

    6. Poll for completion

    Returns an object keyed by network name. Each entry contains the chain configuration and supported tokens.

    Use chainId and token address values from this response when building a scan request.

    Request body:

    Field
    Type
    Required
    Description

    The response is NDJSON — each line is a separate JSON object:

    Success line:

    Error line (route could not be evaluated):

    Collect the simulation objects from success lines. Routes arrive in arbitrary order, so sort by amountOut descending to find the best route and pass it to the next step.

    You can also use POST /routing/scan which returns all routes as a single JSON array. The request body is the same. Each array item has the same shape as the simulation object above.

    Request body:

    Field
    Type
    Required
    Description

    Pass the entire route object as routing. Do not modify or cherry-pick fields from it.

    Response when buildCalldata is true:

    Response when buildCalldata is false or omitted:

    If the input token is an ERC-20 (not the native token), approve the router contract to spend your tokens before sending the swap transaction. The router address is the to field from the /tx/create response.

    Skip this step if the input token is the chain's native token (ETH, MATIC, etc.) — native tokens do not require approval.

    For ERC-4337 and EIP-7702 wallets, the approval is already included in the calls[] array returned by /tx/create. This step applies only to EOA transactions.

    Send the transaction on-chain using your wallet or signer.

    After the transaction is confirmed, extract the requestId from the ComplexOpProcessed event in the receipt:

    Poll GET /transaction/{requestId} until the status reaches a final state.

    See Transaction Tracking for response format and polling recommendations.


    No

    Recipient address (defaults to sender)

    params.tokenIn

    string

    Yes

    Input token address

    params.amountIn

    string

    Yes

    Amount in smallest token units

    params.chainIdIn

    number

    Yes

    Source chain ID

    params.tokenOut

    string

    Yes

    Output token address

    params.chainIdOut

    number

    Yes

    Destination chain ID

    slippage

    number

    Yes

    Slippage tolerance in percent

    feeShareBps

    number

    No

    Partner fee in basis points (100 = 1%)

    providers

    string[]

    No

    Filter by provider: "cross-curve", "rubic", "bungee"

    Yes

    Recipient address

    routing

    object

    Yes

    The simulation object from /routing/scan/stream (or array item from /routing/scan)

    buildCalldata

    boolean

    No

    When true, returns encoded calldata ready to send

    from

    string

    Yes

    Sender address

    recipient

    from

    string

    Yes

    Sender address

    recipient

    Step 1: Get Networks and Tokens

    Step 2: Find a Route

    Step 3: Build the Transaction

    Step 3: Approve Token Spending (ERC-20 only)

    Step 4: Send Swap Transaction

    Step 5: Extract requestId

    Step 6: Poll for Completion

    Full Example (JavaScript + ethers.js)

    Full Example (TypeScript + viem)

    string

    string

    GET /networks
    {
      "sepolia": {
        "name": "sepolia",
        "chainId": 11155111,
        "router": "0x...",
        "tokens": [
          {
            "chainId": 11155111,
            "address": "0x...",
            "name": "USD Coin",
            "symbol": "USDC",
            "decimals": 6,
            "tags": ["erc20", "stable"],
            "permit": false
          }
        ]
      }
    }
    POST /routing/scan/stream
    {
      "from": "0xYOUR_WALLET_ADDRESS",
      "recipient": "0xRECIPIENT_ADDRESS",
      "params": {
        "tokenIn": "0xTOKEN_IN",
        "amountIn": "1000000",
        "chainIdIn": 11155111,
        "tokenOut": "0xTOKEN_OUT",
        "chainIdOut": 64165
      },
      "slippage": 1
    }
    { "route": [...], "simulation": { /* route object — see Routing Response */ } }
    { "route": [...], "error": "error message" }
    POST /tx/create
    {
      "from": "0xYOUR_WALLET_ADDRESS",
      "recipient": "0xRECIPIENT_ADDRESS",
      "routing": { },
      "buildCalldata": true
    }
    {
      "to": "0xROUTER_ADDRESS",
      "data": "0xENCODED_CALLDATA...",
      "value": "0"
    }
    {
      "to": "0xROUTER_ADDRESS",
      "abi": "[...]",
      "args": [...],
      "value": "0"
    }
    // Check current allowance
    const allowance = await tokenContract.allowance(walletAddress, tx.to);
    
    if (allowance < BigInt(route.amountIn)) {
      await tokenContract.approve(tx.to, route.amountIn);
    }
    const COMPLEX_OP_TOPIC = "0x830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c";
    const log = receipt.logs.find((l) => l.topics[0] === COMPLEX_OP_TOPIC);
    const requestId = log.topics[2]; // currentRequestId (bytes32)
    import { ethers } from "ethers";
    
    const API = "https://api.crosscurve.fi";
    const API_KEY = "YOUR_API_KEY";
    
    const provider = new ethers.JsonRpcProvider("https://YOUR_RPC_URL");
    const signer = new ethers.Wallet("0xYOUR_PRIVATE_KEY", provider);
    const WALLET_ADDRESS = signer.address;
    
    const TOKEN_IN = "0xTOKEN_IN";
    const TOKEN_OUT = "0xTOKEN_OUT";
    const CHAIN_ID_IN = 11155111;
    const CHAIN_ID_OUT = 64165;
    const AMOUNT_IN = "1000000"; // in smallest token units
    
    const ERC20_ABI = [
      "function approve(address spender, uint256 amount) returns (bool)",
      "function allowance(address owner, address spender) view returns (uint256)",
    ];
    
    // Helper: parse NDJSON stream into an array of route objects
    async function scanRoutes(body) {
      const response = await fetch(`${API}/routing/scan/stream`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Accept": "application/x-ndjson",
          "api-key": API_KEY,
        },
        body: JSON.stringify(body),
      });
    
      const reader = response.body.getReader();
      const decoder = new TextDecoder();
      const routes = [];
      let buffer = "";
    
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        buffer += decoder.decode(value, { stream: true });
        let idx;
        while ((idx = buffer.indexOf("\n")) >= 0) {
          const line = buffer.slice(0, idx).trim();
          buffer = buffer.slice(idx + 1);
          if (!line) continue;
          const parsed = JSON.parse(line);
          if (parsed.simulation) routes.push(parsed.simulation);
        }
      }
      if (buffer.trim()) {
        const parsed = JSON.parse(buffer);
        if (parsed.simulation) routes.push(parsed.simulation);
      }
    
      return routes;
    }
    
    // Step 1: Find a route
    const routes = await scanRoutes({
      from: WALLET_ADDRESS,
      recipient: WALLET_ADDRESS,
      params: {
        tokenIn: TOKEN_IN,
        amountIn: AMOUNT_IN,
        chainIdIn: CHAIN_ID_IN,
        tokenOut: TOKEN_OUT,
        chainIdOut: CHAIN_ID_OUT,
      },
      slippage: 1,
    });
    routes.sort((a, b) => {
      if (BigInt(a.amountOut) > BigInt(b.amountOut)) return -1;
      if (BigInt(a.amountOut) < BigInt(b.amountOut)) return 1;
      return 0;
    });
    const route = routes[0];
    
    // Step 2: Build the transaction
    const txRes = await fetch(`${API}/tx/create`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        from: WALLET_ADDRESS,
        recipient: WALLET_ADDRESS,
        routing: route,
        buildCalldata: true,
      }),
    });
    const tx = await txRes.json();
    
    // Step 3: Approve router if input is ERC-20 (skip for native token)
    const tokenContract = new ethers.Contract(TOKEN_IN, ERC20_ABI, signer);
    const allowance = await tokenContract.allowance(WALLET_ADDRESS, tx.to);
    if (allowance < BigInt(route.amountIn)) {
      const approveTx = await tokenContract.approve(tx.to, route.amountIn);
      await approveTx.wait();
    }
    
    // Step 4: Send swap on-chain
    const swapTx = await signer.sendTransaction({
      to: tx.to,
      data: tx.data,
      value: tx.value,
    });
    const receipt = await swapTx.wait();
    
    // Step 5: Extract requestId from receipt
    const COMPLEX_OP_TOPIC = "0x830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c";
    const log = receipt.logs.find((l) => l.topics[0] === COMPLEX_OP_TOPIC);
    const requestId = log.topics[2]; // currentRequestId (bytes32)
    
    // Step 6: Poll for completion
    async function pollStatus(requestId) {
      while (true) {
        const res = await fetch(`${API}/transaction/${requestId}`);
        const status = await res.json();
    
        console.log("Status:", status.status);
    
        if (["completed", "failed", "reverted", "canceled"].includes(status.status)) {
          return status;
        }
    
        await new Promise((r) => setTimeout(r, 12000));
      }
    }
    
    const result = await pollStatus(requestId);
    console.log("Final status:", result.status);
    import { createWalletClient, createPublicClient, http, parseAbi, parseEventLogs } from "viem";
    import { privateKeyToAccount } from "viem/accounts";
    import { sepolia } from "viem/chains";
    
    const API = "https://api.crosscurve.fi";
    const API_KEY = "YOUR_API_KEY";
    
    const TOKEN_IN = "0xTOKEN_IN";
    const TOKEN_OUT = "0xTOKEN_OUT";
    const CHAIN_ID_IN = 11155111;
    const CHAIN_ID_OUT = 64165;
    const AMOUNT_IN = "1000000";
    
    const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
    const publicClient = createPublicClient({ chain: sepolia, transport: http() });
    const walletClient = createWalletClient({
      account,
      chain: sepolia,
      transport: http(),
    });
    
    // Helper: parse NDJSON stream into an array of route objects
    async function scanRoutes(body: Record<string, unknown>) {
      const response = await fetch(`${API}/routing/scan/stream`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Accept": "application/x-ndjson",
          "api-key": API_KEY,
        },
        body: JSON.stringify(body),
      });
    
      const reader = response.body!.getReader();
      const decoder = new TextDecoder();
      const routes: unknown[] = [];
      let buffer = "";
    
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        buffer += decoder.decode(value, { stream: true });
        let idx: number;
        while ((idx = buffer.indexOf("\n")) >= 0) {
          const line = buffer.slice(0, idx).trim();
          buffer = buffer.slice(idx + 1);
          if (!line) continue;
          const parsed = JSON.parse(line);
          if (parsed.simulation) routes.push(parsed.simulation);
        }
      }
      if (buffer.trim()) {
        const parsed = JSON.parse(buffer);
        if (parsed.simulation) routes.push(parsed.simulation);
      }
    
      return routes;
    }
    
    // Step 1: Find a route
    const routes = await scanRoutes({
      from: account.address,
      recipient: account.address,
      params: {
        tokenIn: TOKEN_IN,
        amountIn: AMOUNT_IN,
        chainIdIn: CHAIN_ID_IN,
        tokenOut: TOKEN_OUT,
        chainIdOut: CHAIN_ID_OUT,
      },
      slippage: 1,
    });
    routes.sort((a: any, b: any) => {
      if (BigInt(a.amountOut) > BigInt(b.amountOut)) return -1;
      if (BigInt(a.amountOut) < BigInt(b.amountOut)) return 1;
      return 0;
    });
    const route = routes[0];
    
    // Step 2: Build the transaction
    const txRes = await fetch(`${API}/tx/create`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        from: account.address,
        recipient: account.address,
        routing: route,
        buildCalldata: true,
      }),
    });
    const tx: { to: string; data: string; value: string } = await txRes.json();
    
    // Step 3: Approve router if input is ERC-20 (skip for native token)
    const erc20Abi = parseAbi([
      "function approve(address,uint256) returns (bool)",
      "function allowance(address,address) view returns (uint256)",
    ]);
    const allowance = await publicClient.readContract({
      address: TOKEN_IN as `0x${string}`,
      abi: erc20Abi,
      functionName: "allowance",
      args: [account.address, tx.to as `0x${string}`],
    });
    if (allowance < BigInt(route.amountIn)) {
      await walletClient.writeContract({
        address: TOKEN_IN as `0x${string}`,
        abi: erc20Abi,
        functionName: "approve",
        args: [tx.to as `0x${string}`, BigInt(route.amountIn)],
      });
    }
    
    // Step 4: Send swap on-chain
    const hash = await walletClient.sendTransaction({
      to: tx.to as `0x${string}`,
      data: tx.data as `0x${string}`,
      value: BigInt(tx.value),
    });
    
    console.log("Transaction sent:", hash);
    
    // Step 5: Extract requestId from receipt
    const receipt = await publicClient.waitForTransactionReceipt({ hash });
    const complexOpAbi = parseAbi([
      "event ComplexOpProcessed(uint64 indexed currentChainId, bytes32 indexed currentRequestId, uint64 indexed nextChainId, bytes32 nextRequestId, uint8 result, uint8 lastOp)",
    ]);
    const events = parseEventLogs({ abi: complexOpAbi, logs: receipt.logs, eventName: "ComplexOpProcessed" });
    const requestId = events[0].args.currentRequestId;
    
    // Step 6: Poll for completion
    async function pollStatus(requestId: string) {
      while (true) {
        const res = await fetch(`${API}/transaction/${requestId}`);
        const status = await res.json();
    
        console.log("Status:", status.status);
    
        if (["completed", "failed", "reverted", "canceled"].includes(status.status)) {
          return status;
        }
    
        await new Promise((r) => setTimeout(r, 12000));
      }
    }

    EYWA pool via Convex

    Curve inflation is directed to EYWA pools on Convex, and now liquidity providers receive incentives in CRV

    For example, the yield in the is currently as follows:

    Base Curve vAPR: 2.69%

    CRV vAPR (incl. 2.5x boost): 212.07%

    Total vAPR: 214.76%

    You can purchase the EYWA token on CEX or DEX. The list of available exchanges can be viewed here:

    or here: https://coinmarketcap.com/currencies/eywa/#Markets

    Let’s consider an example of purchasing the EYWA token with USDT on the CrossCurve DEX.

    EYWA tokens can be purchased on CrossCurve for any assets available in the app (USDT, USDC, crvUSD, DAI, ETH, BTC etc.)

    Go to https://crosscurve.fi and use the quick link Buy EYWA → Buy on CrossCurve and click Connect wallet

    Select the wallet installed in your system and confirm the connection to the application in your wallet

    After successfully connecting the wallet, the application will direct you to the EYWA - USDT trading pair on the Arbitrum network. Enter the desired amount for exchange and click Approve USDT

    Sign the USDT spending transaction in your wallet

    To complete the exchange, click Swap

    Sign the exchange transaction in your wallet

    Wait for the on-chain transaction to complete

    Go to the Liquidity page in the Yield section

    In the Choose pool list, select EYWAUSDT pool, the Deposit operation, the Easy mode operation type, and click Next

    Enter the amount of EYWA tokens and click Approve EYWA

    Sign the EYWA spending transaction in your wallet

    To complete the transaction, click Swap

    Sign the exchange transaction in your wallet

    Wait for the on-chain transaction to complete

    Go to the Stake page in the Curve section on https://curve.convexfinance.com/stake and connect your wallet

    In the Stake Curve LP Tokens section, select Arbitrum One chain, enter EYWA in the Search pools field and the application will display USDT+EYWA pool

    Enter the amount of EYWAUSDT LP tokens and click Approve

    Sign the EYWAUSDT LP spending transaction in your wallet

    To stake EYWAUSDT LP, click Deposit & Stake

    Sign the depositing & staking transaction in your wallet

    After the on-chain transaction is completed, the provided liquidity will be displayed in the My Deposits field, and the accrued rewards will be displayed in the Claimable field

    To achieve this yield, you need to complete a few simple steps:

    Purchasing the EYWA token

    USDT+EYWA pool
    https://www.coingecko.com/en/coins/eywa

    CrossCurve DEX

    Attention! Be aware of possible high slippage before making an exchange to avoid loss of funds.

    To purchase EYWA with USDT, you need to have USDT in your wallet on the Arbitrum network and ETH in the Arbitrum network to pay for transaction gas in Gwei (gas cost can be checked here - ).

    Providing liquidity in the USDT+EYWA pool

    https://arbitrum.blockscout.com/gas-tracker

    DelegationManagerV1

    Overview

    DelegationManagerV1 This is an upgradeable contract that allows you to delegate your locks to another account. This contract is integrated with EmissionManager, EscrowManager, EscrowVoteManager, LockHolderFactory, RebaseRewardsDistributor, DelegationConditionValidator. It allows the lock owner to delegate or automate actions such as voting and collecting rebase rewards and incentive rewards.

    Key Roles and Features:

    1. Access Control: Restricts setAssuranceLockParameters and setMinLockVeEywa calls to the owner of contract(owner()).

    2. Upgradeable via UUPS: Uses UUPSUpgradeable and OwnableUpgradeable patterns, restricting contract upgrades to the owner.


    • UUPSUpgradeable (OpenZeppelin): Provides upgrade functionality under the UUPS proxy pattern, restricted to the contract owner.

    • OwnableUpgradeable (OpenZeppelin): Manages ownership, allowing only the owner to modify critical parameters and authorize upgrades.

    • IDelegationManagerV1: Defines core methods (e.g., setDelegationParameters, delegate

    Additional External References:

    • SafeERC20, IERC20 (OpenZeppelin): Handles secure ERC20 operations for distributing and approving token transfers.

    • IRebaseRewardsDistributorV2: Distributes rebase rewards and triggers relevant accounting updates.

    • IDelegationConditionValidatorV1: Logic to test additional conditions for delegation


    • EPOCH_DURATION: Duration of each emission/gauge epoch (1 week).

    • PRECISION: The divisior for percentage math.


    • s_eywa (IERC20) ERC20 token interface for the EYWA token.

    • s_collection (ICollection) ICollection Interface for the NFT collection contract.

    • s_emissionManager (IEmissionManagerV1)


    • Description: Disables contract initializers to prevent re-initialization in a UUPS proxy context.


    Description: Configures ownership, references, and initial state:

    • Sets s_minLockEywa to 500 000 * 1e18 initially.

    • Sets s_minLockVeEywa to 1 000 * 1e18 initially.

    • Sets s_minLockDuration to 52 weeks initially.

    Parameters:

    • owner_: The address of the contract owner.

    • eywa_: ERC20 token interface for the EYWA token.

    • collection_: ICollection Interface for the NFT collection contract.


    Description: Setting parameters for the delegate assurance lock

    Parameters:

    Checks:

    • Only the owner of the contract can call this function.


    Description: Setting the minimum veEYWA value for delegated locks

    Parameters:

    • minLockVeEywa_: The minimum number of veEYWA that must be in the delegated lock.

    Checks:

    • Only the owner of the contract can call this function.


    Description: Setting delegation parameters for the delegate If this is the first time a delegate is setting parameters, its address is added to the delegate array (s_delegaties) delegationParameters_.eywaDeposit and the delegate's current deposit. Delegation parameters can only be changed once the rewards have been received and distributed and rent has been paid for all delegated locks. When one or more parameters are changed: delegationParameters_.maxDelegatedVeEYWA, delegationParameters_.delegationEnd, delegationParameters_.eywaDeposit - the rent per veEYWA unit per epoch is recalculated. Performs a transfer of the required number of EYWA tokens from the delegate's account to his deposit in the contract. This deposit will be used to pay for lock rentals to delegates. The required number is calculated as the difference between

    Parameters:

    • delegationParameters_: Parameters of the delegation.

    Checks:

    • The delegate must pass the correct parameters. Otherwise, WrongDelegationParameters() is thrown.

    • The delegate assuranceLock lock must comply with the requirements set forth. Otherwise, BadAssuranceLock() is thrown.

    • All rewards for all delegated locks must be received. Otherwise, RewardsUnclaimed()


    Description: Setting the parameters auto-voting for a specific delegate.

    Parameters:

    • pools_: The array of voting pools.

    • weights_: The array with voice weights for each pool.

    Checks:

    • pools_ and weights_ arrays must not be null and must have the same size. Otherwise, InvalidArrayLengths() is thrown.


    Description: Set the permission for automatic voting using the autoVote function. With this permission, this autoVote function can be called by any account. To perform automatic voting, you must set the parameters with the setDelegationVoteParameters function

    Parameters:

    • permission_: The permission parameter.


    Description: The function proxies the call of the boost function on the EscrowManager contract.

    Parameters:

    • tokenId_: The ID of the token representing the lock.

    • collectionTokenIds_: An array of token IDs from the collection that will be used to boost the lock.

    Checks:

    • The lock must be self-delegation and the caller must be a delegator. Otherwise, UnauthorizedCaller() is thrown.

    • Delegation time should not be finalized. Otherwise, DelegateTimeExpired() is thrown.


    Description: The function proxies the call of the deboost function on the EscrowManager contract. And then performs a transfer of the NFTs withdrawn from the lock to the delegator balance.

    Parameters:

    • tokenId_: The ID of the token representing the lock.

    • collectionTokenIds_: An array of token IDs from the collection that will be used to boost the lock.

    Checks:

    • The lock must be self-delegation and the caller must be a delegator. Otherwise, UnauthorizedCaller() is thrown.


    Description: The function proxies the call of the extend function on the EscrowManager contract.

    Parameters:

    • tokenIds_: An array of IDs of the token representing the lock.

    • collectionTokenIds_: An array of token IDs from the collection that will be used to boost the lock.

    Checks:

    • The tokenIds_ and lockDurations_ arrays must have the equal length. Otherwise, InvalidArrayLengths() is thrown.

    • For each lock from tokenIds delegatee_ must be a delegator. Otherwise, WrongDelegatee() is thrown.


    Description: Function for deposit withdrawal. Performs transfer of amount_ of EYWA tokens from contract balance to msg.sender balance. Decreases by amount_ the value in s_depositByDelegatee on the msg.sender key. A delegate can only withdraw a deposit if the current delegation has been completed and all payments for all delegated locks have been made.

    Parameters:

    • amount_: The amount of EYWA tokens.

    Checks:

    • Checks that the delegate's deposit is not less than amount_. Otherwise, NotEnoughAmount() is thrown.

    • Fee must be paid for each delegated lock. Otherwise, DelegationUnpaid() is thrown.


    Description: The function transfers EYWA, received as a commission for delegated locks, to the balance of the delegator


    Description: This function performs a number of necessary checks, after which the internal function _delegate() is called, in which delegation takes place.

    Parameters:

    • delegatee_: The delegate's address.

    • tokenIds_: An array of IDs of the token representing the lock.

    Checks:

    • If it is not a self-delegation, it is checked that delegatee_ has set the delegation parameters. Otherwise, DelegateeNotExist() is thrown.

    • If it is not self-delegation, it is verified that the condition of the assurance lock is as specified. Otherwise, BadAssuranceLock() is thrown.

    Events:

    • Emits Delegate(delegator, delegatee, tokenIds).


    Description: The function transfers lock commissions from the delegatee's deposit to the delegator's deposit, for all epochs since the last time the commission was received, and renews locks

    Parameters:

    • tokenIds_: An array of IDs of the token representing the lock.


    Description: The function proxies the call of the claimIncentives function on the LockHoldeV1 contract. After collecting and distributing the bounty, notes that the bounty for the specified locks is received in this epoch.

    Parameters:

    • tokenIds_: An array of IDs of the token representing the lock.


    Description: Function to revoke the delegation. Sets the start of the next epoch to the time the delegation ends. After the start of the next epoch, these delegated locks cannot be voted on.

    Parameters:

    • tokenIds_: An array of IDs of the token representing the lock.

    Checks:

    • For each lock from tokenIds_, it is checked that the function is called by a delegator or delegate. Otherwise, UnauthorizedCaller() is thrown.

    • For each lock from tokenIds_, it is checked that its delegation time has not yet expired. Otherwise, DelegateTimeExpired() is thrown.


    Description: Delegation Completion Function. In the normal situation, this function is called in the next epoch, after the revokeDelegations function has been called. For self-delegated locks, this function can be called at any time, without first calling the revokeDelegations function. If the delegation time specified in the delegation parameters has expired, you can call this function, without first calling the revokeDelegations function. After partitioning a lock, reduces by its veEYWA value the amount of veEYWA delegated to the delegate.

    Parameters:

    • tokenIds_: An array of IDs of the token representing the lock.

    Checks:

    • You can't recall assurance lock. Otherwise, DelegationWithdrawalForbidden() is thrown.

    • For each lock from tokenIds_, it is checked that the function is called by a delegator or delegate. Otherwise, UnauthorizedCaller() is thrown.

    • All rewards for all delegated locks must be received. Otherwise,

    Events:

    • Emits RecallDelegations(tokenIds_).


    Description: The function proxies the call of the extend function on the EscrowVoteManager contract.

    For each lock from tokenIds_ the necessary checks are performed in the internal function _checkDelegation, which will be described in detail below

    Parameters:

    • tokenIds_: An array of IDs of the token representing the lock.

    • pools_: An array of voting pools.

    • weights_: An array with voice weights for each pool.


    Description: The function proxies the call of the extend function on the EscrowVoteManager contract.

    The delegate must set permission for auto-voting in the setAutoVotePermission function and set the voting parameters in the setDelegationVoteParameters function. Then any account can perform voting by delegated locks of this delegate using the set parameters.

    For each lock from tokenIds_ the necessary checks are performed in the internal function _checkDelegation, which will be described in detail below

    Parameters:

    • delegatee_: An array of IDs of the token representing the lock.

    • tokenIds_: An array of IDs of the token representing the lock.

    Checks:

    • The delegatee_ must set the authorization for auto-voting. Otherwise, NotSetAutoVote() is thrown.

    • The delegatee_ must set the parameters for auto-voting. Otherwise, NotSetAutoVoteParameters() is thrown.


    Description: The function proxies the call of the reset function on the EscrowVoteManager contract.

    For each lock from tokenIds_ the necessary checks are performed in the internal function _checkDelegation, which will be described in detail below.

    Parameters:

    • tokenIds_: An array of IDs of the token representing the lock.


    Description: The function proxies the call of the poke function on the EscrowVoteManager contract.

    For each lock from tokenIds_ the necessary checks are performed in the internal function _checkDelegation, which will be described in detail below.

    Parameters:

    • tokenIds_: An array of IDs of the token representing the lock.


    Description: The function checks all current delegation parameters accepts determines whether delegation from delegator_ to delegatee_ of tokenIds_ locks is possible. Returns true/false - delegation is or is not possible for the given values

    Parameters:

    • delegator_: The delegator's address.

    • delegatee_: The delegate's address.

    • tokenIds_: An array of IDs of the token representing the lock.


    Description: The function returns an array of parameters of all delegates


    Description: The function returns the auto-voting parameters for a specific delegatee_

    Parameters:

    • delegatee_: The delegate's address.


    Description: The function returns an array with delegation information for an array of delegations

    Parameters:

    • tokenIds_: An array of IDs of the token representing the lock.


    Description: The function returns delegation information delegationInfo_ and delegation parameters delegationParameters_ for a specific delegated lock by its tokenId_

    Parameters:

    • tokenId_: The ID of the token representing the lock.


    Description: The function returns an array of id's of all locks delegated by the delegator_

    Parameters:

    • delegator_: The delegator's address.


    Description: The function returns an array of id's of all locks delegated to the delegatee_

    Parameters:

    • delegatee_: The delegate's address.


    Description: The function checks and returns true/false the status of tokenId_ as a Assurance lock for the delegatee_

    Parameters:

    • tokenId_: The ID of the token representing the lock.

    • delegatee_: The delegate's address.


    Description: The delegation function performs the necessary checks and then performs a lock transfer to the LockHolder contract, and the entire veEYWA of the lock is transferred to the delegate_ account. If this sender delegates locks to this delegate_ for the first time, a new LockHolder contract is deployed for them. The necessary data structures are also created to store information about the delegated lock. If a sender address or null address is specified as delegate_, self-delegation occurs.

    Parameters:

    • escrowManager_: The IEscrowManagerExtended interface for the EscrowManager contract.

    • delegationParameters_: Parameters of the delegation.

    • tokenIds_: The array of IDs of the token representing the lock.

    Checks

    • If it is not a self-delegation, checked that the veEYWA value of all lots specified in tokenIds_ is not less than the s_minLockVeEywa value set in the contract minVeEYWA set in delegations parameters. Otherwise, WrongVeEywaAmount() is thrown.

    • If it is not self-delegation, checks that the time to unlock the lock is not lower than the minimum time set by the delegatee_. Otherwise, LittleTimeToUnlock()


    Description: Delegation recall function

    First, a check is made to see if the vote was made by this tokenId_, and if so, the reset function is called on the LockHolder contract to reset the vote. Otherwise it will be impossible to perform a lock transfer.

    The data structures are then overwritten and the data of the revocable delegation is deleted.

    At the end, a transfer of the voiting power and lock token to the delegator address is made

    Checks:

    • For tokenId_, it is checked that there exists a LockHolder contract corresponding to the delegate-delegate pair. Otherwise, LockHolderNotExist() is thrown.

    Parameters:

    • delegator_: The delegator's address.

    • delegatee_: The delegate's address.

    • tokenId_ The ID of the token representing the lock.


    Description: Returns the sum of veEYWA from an array of locks tokenIds_

    Parameters:

    • tokenIds_: The array of IDs of the token representing the lock.


    Description: The function returns the completion time of the delegation

    Parameters:

    • timeExpiry_: The expiry timestamp to verify.

    • delegationEnd_: The epoch in which the delegation will be completed.


    Description: The function returns the start time of the last paid epoch

    Parameters:

    • timeExpiry_: The expiry timestamp to verify.

    • delegationEnd_: The epoch in which the delegation will be completed.

    • currentEpochStart_: The start time of the current epoch.


    Description: The function checks whether the delegation has been paid in the current epoch. Returned with DelegationUnpaid if the delegation is not paid in the current epoch.

    Parameters:

    • isSelfDelegation_: Indicates whether the delegation is self-delegated.

    • lastPaidEpoch_: An epoch when the last fee payment was made.

    • paidEpoch_: An epoch that must be paid for.

    Checks

    • Unless it is self-delegation, the last epoch paid should not be less than the epoch to be paid. Otherwise, DelegationUnpaid() is thrown.


    Description: The function checks to see if available awards have been received. Returned with RewardsUnclaimed if no awards have been received.

    Parameters:

    • tokenId_: Indicates whether the delegation is self-delegated.

    • currentEpochStart_: The current epoch start.

    • lockHolder_: The lock holder contract address.

    Checks

    • Unless it is self-delegation, the last epoch paid should not be less than the epoch to be paid. Otherwise, DelegationUnpaid() is thrown.


    Description: Internal function to check the caller.

    Parameters:

    • caller_: The expected caller's address.

    Checks:

    • msg.sender must be equal to caller_. Otherwise, UnauthorizedCaller() is thrown.


    Description: Internal function to verify that the function caller is a delegate or delegator.

    Parameters:

    • delegator_: The delegator's address.

    • delegatee_: The delegate's address.

    Checks:

    • msg.sender must be equal to delegator_ or delegatee_. Otherwise, UnauthorizedCaller() is thrown.


    Description: Internal function to check that the delegation time has not expired. If the delegation has been revoked and timeExpiry is not equal to 0, the end time of the delegation must be less than the current time

    Parameters:

    • timeExpiry_: The end time of delegation.

    Checks:

    • block.timestamp must be not equal 0 and greater than timeExpiry_. Otherwise, DelegateTimeExpired() is thrown


    Description: Internal Function to check the LockHolder contract address for a pair of delegator and delegate. Returns the LockHolder contract's address.

    Parameters:

    • delegator_: The delegator's address.

    • delegatee_: The delegate's address.

    Checks:

    • a LockHolder contract must be deployed for the delegator_ and delegatee_ pair. Otherwise, LockHolderNotExist() is thrown


    Description: Internal function to check the assurance lock. Verification that the lock is a self-made lock, or its assurance lock meets the specified requirements

    Parameters:

    • assuranceLock_: The token ID used as the assurance lock.

    • delegatee_: The delegatee assurance lock.

    Checks:

    • If the conditions are not met for assuarnce lock. Otherwise, BadAssuranceLock() is thrown


    Description: Internal function for check the delegation status. Check caller, time expiry, delegation fee payment. A number of internal functions are called for the checks, which will be described below

    Parameters:

    • delegationInfo_: The delegation information associated with the token.

    • caller_: The expected caller's address.

    • currentEpochStart_: The current epoch start.

    Checks:

    • The start time of the current epoch must be less than the end time of the delegation. Otherwise, DelegationEnded() is thrown.


    Description: Internal function for checking self-delegation. Returns the LockHolder contract's address.

    Parameters:

    • tokenId_: The ID of the token representing the lock.

    Checks:

    • When self-delegating for tokenId_, the delegator must be equal to the delegate and both of these values must be equal to msg.sender. Otherwise, UnauthorizedCaller() is thrown


    Description: The function returns the start timestamp of the current epoch


    Description: The function returns the start timestamp of the next epoch


    Description: The function returns the time until the lock is unlocked

    Parameters:

    • tokenId_: The ID of the token representing the lock.


    Description: Internal function to check if the delegate has set the delegation parameters

    Parameters:

    • delegatee_: The delegate's address.

    Checks:

    • delegatee_ must have delegation parameters set. Otherwise, DelegateeNotExist() is thrown.


    • Delegate(address indexed delegator, address indexed delegatee, uint256[] tokenIds) The event is emitted when the delegation is successful.

    • RecallDelegations(uint256[] tokenIds) The event is emitted when the recall delegation is successful.


    • WrongDelegationParameters() Thrown if the delegate tries to set the wrong delegation parameters.

    • BadAssuranceLock() Thrown if the assurance lock is not compliant.

    • DelegateeNotExist()


    DelegationManagerV1 contract allows the castle owner not to track voting and reward collection, and not to spend ether on transaction fees. The delegate, on the other hand, can earn by taking a percentage of the rewards, sharing them with the castle owner. Alternatively, the castle owner can delegate to himself, which would simply automate the execution of voting and collection of rebase rewards and incentive rewards.

    ERC-4337 Smart Account Swap

    For smart wallets using the ERC-4337 standard (Pimlico, ZeroDev, etc.). The routing step is identical to the EOA flow — use POST /routing/scan/stream (see Find a Route). The difference is in the /tx/create request and response.

    Four gas payment modes are available:

    • Mode A -- ERC-20 paymaster: gas is paid in an ERC-20 token (e.g. USDC) via the CrossCurve Pimlico proxy.

    ,
    vote
    ) and events for this contract.
    ILockHolderFactoryV1: Deployment of new LockHolder contracts
  • IEscrowManagerExtended: Holds locked token data and checks voting power and freeze logic.

  • IEscrowVoteManagerV1: Receives gauge emission amounts and coordinates gauge reward distribution.

  • IEmissionManagerV1: Informs about epoch starts and ensures updated weekly distributions.

  • ILockHolderV1: Logic for proxied calls to EscrowManager, EscrowVoteManager and IncentiveRewardsDistributor contract functions

  • ICollection: Components in the ecosystem for NFT.

  • IEmissionManagerV1 interface for the EmissionManagerV1 contract.
  • s_escrowManager (IEscrowManagerExtended) IEscrowManager interface for the EscrowManager contract.

  • s_escrowVoteManager (IEscrowVoteManagerV1) IEscrowVoteManagerV1 interface for the EscrowVoteManager contract.

  • s_lockHolderFactory (ILockHolderFactoryV1) ILockHolderFactoryV1 interface for the LockHolderFactoryV1 contract.

  • s_rebaseRewardsDistributor (IRebaseRewardsDistributorV2) IRebaseRewardsDistributorV2 interface for the RebaseRewardsDistributorV2 contract.

  • s_delegationConditionValidator (IDelegationConditionValidatorV1) IDelegationConditionValidatorV1 interface for the DelegationConditionValidator contract.

  • s_minLockEywa (uint256) The min EYWA amount in delegatee's lock.

  • s_minLockVeEywa (uint256) The min veEYWA amount in delegatee's lock.

  • s_minLockDuration (uint256) The min duration for delegatee's lock in seconds.

  • s_delegaties (address[]) Array with addresses of all delegates.

  • s_depositedByDelegatee (mapping(address => uint256)) Mapping from delegatee to its EYWA deposit information.

  • s_feeByDelegator (mapping(address => uint256)) Mapping from delegator to its EYWA fee information.

  • s_autoVoteByDelegatee (mapping(address => bool)) Mapping from delegatee to its permission for automatic execution of the autoVote() function.

  • s_delegationParametersByDelegatee (mapping(address => DelegationParameters)) Mapping from delegatee to its delegation parameters.

  • s_delegationInfoByTokenId (mapping(address => DelegationInfo)) Mapping from token ID to its delegation information.

  • s_lastClaimedIncentiveTimeByLockHolder (mapping(address => uint256)) Mapping from LockHolder contract address to its last time claimed incentive.

  • s_lastClaimedCommissionTimeByLockHolder (mapping(address => uint256)) Mapping from LockHolder contract address to its last time claimed commission.

  • s_lockHolders (mapping(address => mapping(address => address))) Nested mapping from delegator and delegatee to their LockHolder contract address.

  • _s_locksByDelegator (mapping(address => uint256)) Mapping from delegator to its amount of delegated locks.

  • _s_locksByDelegatee (mapping(address => uint256)) Mapping from delegatee to its amount of delegated locks.

  • _s_delegationVoteParametersByDelegatee (mapping(address => DelegationVoteParameters)) Mapping from delegatee to its delegation vote parameters.

  • _s_delegationIndexesInfoByTokenId (mapping(address => DelegationIndexesInfo)) Mapping from token ID to its delegation indexes info.

  • _s_lockIdByDelegatorAndIndex (address => mapping(uint256 => uint256)) Nested mapping from delegator and index to its delegated lock ID.

  • _s_lockIdByDelegateeAndIndex (address => mapping(uint256 => uint256)) Nested mapping from delegatee and index to its delegated lock ID.

  • _s_feeByDelegateeAndEpoch (mapping(address => mapping(uint256 => uint256))) Nested mapping of delegatee address and an epoch start to a fee.

  • References the EYWA token, EYWA NFT, escrow manager, escrow vote manager, emission manager, lockHolder factory, rebase rewards distributor, delegation condition validator.

    emissionManager_: IEmissionManagerV1 interface for the EmissionManagerV1 contract.

  • escrowManager_: The IEscrowManagerExtended interface for the EscrowManager contract.

  • escrowVoteManager_: The IEscrowVoteManagerV1 interface for the EscrowVoteManager contract.

  • lockHolderFactory_: ILockHolderFactoryV1 interface for the LockHolderFactoryV1 contract.

  • rebaseRewardsDistributor_: IRebaseRewardsDistributorV2 interface for the RebaseRewardsDistributorV2 contract.

  • delegationConditionValidator_: IDelegationConditionValidatorV1 interface for the DelegationConditionValidator contract.

  • is thrown.
  • Must be paid rent for all delegated tokens. Otherwise, DelegationUnpaid() is thrown.

  • The value of delegationParameters_.maxDelegatedVeEYWA must not be less than the current total veEYWA value for all locks delegated to this delegate. Otherwise, MaxDelegatedVeEywaExceeded() is thrown.

  • For each lock from tokenIds_, it is checked that its delegation time has not yet expired. Otherwise, DelegateTimeExpired() is thrown.

  • The maximum veEYWA value for dlegation should not be exceeded after extend of the locks. Otherwise, MaxDelegatedVeEywaExceeded() is thrown.

  • For each lock from tokenIds_, it is checked that there exists a LockHolder contract corresponding to the delegate-delegate pair. Otherwise, LockHolderNotExist() is thrown.

  • If it is not a self-delegation, iit is checked that the maximum number of veEYWA specified in the delegation parameters will not be exceeded. Otherwise, MaxDelegatedVeEywaExceeded() is thrown.
  • If it is not a self-delegation, additional delegation conditions are checked in the validateDelegations function on the DelegationConditionValidator contract. Otherwise, UnvalidatedDelegation() is thrown.

  • RewardsUnclaimed()
    is thrown.
  • Must be paid rent for all delegated tokens. Otherwise, DelegationUnpaid() is thrown.

  • The delegation's time must be finalized. Otherwise, DelegationWithdrawalForbidden() is thrown.

  • For each lock from tokenIds delegatee_ must be a delegatee. Otherwise, WrongDelegatee() is thrown.

    delegatee_: The delegate's address.

    is thrown.
    Thrown if the delegate has not set the delegation parameters.
  • InvalidArrayLengths() Thrown if the array has an invalid length.

  • UnauthorizedCaller() Thrown when the caller is not authorized to perform the action.

  • DelegateTimeExpired() Thrown when attempting to perform an action with a delegation with expired time.

  • DelegationEnded() Thrown when the delegation is complete.

  • WrongLockDuration() Thrown when attempting to set a new lock auto-extend time lower than the minimum allowed by the delegation parameters.

  • LockHolderNotExist() Thrown if there is no LockHolder for the current delegate and delegate pair.

  • NotEnoughAmount() Thrown when there is an insufficient deposit or fee for the requested operation.

  • DelegationNotEnded() Thrown when the delegation is not ended.

  • MaxDelegatedVeEywaExceeded() Thrown when the maximum number of delegated veEYWA has been exceeded.

  • UnvalidatedDelegation() Thrown when validation failed on the DelegationConditionValidator contract.

  • WrongVeEywaAmount() Thrown when the voting power of the delegated lock is less than s_minLockVeEywa.

  • LittleTimeToUnlock() Thrown when attempting to delegate a lock that has less time to unlock than the minimum time set by the delegate.

  • NotSetAutoVote() Thrown when attempting to perform auto-voting if no permission is set.

  • NotSetAutoVoteParameters() Thrown when attempting to perform auto-voting if no parameters are set for it.

  • WrongDelegatee() Thrown when attempting to perform an auto-vote if the lock is not delegated to the specified delegate.

  • DelegationWithdrawalForbidden() Thrown when the delegation time has not yet expired, preventing recall.

  • RewardsUnclaimed() Thrown when the delegation time has not yet expired, preventing recall.

  • DelegationUnpaid() Thrown when no awards have been received.

  • Inherited Contracts and Interfaces

    Constants

    State Variables

    Constructor

    External Functions (Defined by IDelegationManagerV1)

    initialize(...)

    setAssuranceLockParameters(uint256 minLockEywa_, uint256 minLockDuration_)

    setMinLockVeEywa(uint256 minLockVeEywa_)

    setDelegationParameters(DelegationParameters memory delegationParameters_)

    setDelegationVoteParameters(address[] calldata pools_, uint256[] calldata weights_)

    setAutoVotePermission(bool permission_)

    boost(uint256 tokenId_, uint256[] calldata collectionTokenIds_)

    deboost(uint256 tokenId_, uint256[] calldata collectionTokenIds_)

    extend(uint256[] calldata tokenIds_, uint256[] calldata lockDurations_)

    withdrawDeposit(uint256 amount_)

    claim()

    delegate(address delegatee_, uint256[] calldata tokenIds_)

    paymentAndExtendDelegations(uint256[] calldata tokenIds_)

    claimIncentives(uint256[] calldata tokenIds_)

    revokeDelegations(uint256[] calldata tokenIds_)

    recallDelegations(uint256[] calldata tokenIds_)

    function vote(uint256[] calldata tokenIds_, address[][] calldata pools_, uint256[][] calldata weights_)

    autoVote(address delegatee_, uint256[] calldata tokenIds_)

    reset(uint256[] calldata tokenIds_)

    poke(uint256[] calldata tokenIds_)

    isAvailableDelegate(address delegator_, address delegatee_, uint256[] calldata tokenIds_)

    getDelegationsParameters()

    getDelegationsVoteParametersByDelegate(address delegatee_)

    getDelegationsInfoByTokenIds(uint256[] calldata tokenIds_)

    getDelegationInfoAndParametersByTokenId(uint256 tokenId_)

    getLockIdsByDelegator(address delegator_)

    getLockIdsByDelegatee(address delegatee_)

    getAssuranceLockStatus(uint256 tokenId_, address delegatee_)

    Internal and Private Functions

    _delegate(IEscrowManagerExtended escrowManager_, DelegationParameters memory delegationParameters_, uint256[] calldata tokenIds_, address delegatee_)

    _recallDelegation(address delegator_, address delegatee_, uint256 tokenId_)

    _getVotes(IEscrowManagerExtended escrowManager_, uint256[] calldata tokenIds_)

    _getLastEpochOfDelegation(uint256 timeExpiry_, uint256 delegationEnd_)

    _getPaidEpoch(uint256 timeExpiry_, uint256 delegationEnd_, uint256 currentEpochStart_)

    _checkDelegationPaid(bool isSelfDelegation_, uint256 lastPaidEpoch_, uint256 paidEpoch_)

    _checkRewardsClaimed(uint256 tokenId_, uint256 currentEpochStart_, address lockHolder_)

    _checkCaller(address caller_)

    _checkDelegatorOrDelegatee(address delegator_, address delegatee_)

    _checkTimeExpiry(uint256 timeExpiry_)

    _checkLockHolder(address delegator_, address delegatee_)

    _checkAssuranceLock(uint256 assuranceLock_, address delegatee_)

    _checkDelegation(DelegationInfo memory delegationInfo_, address caller_, uint256 currentEpochStart_)

    _checkForSelfDelegation(uint256 tokenId_)

    _currentEpochStart()

    _nextEpochStart()

    _getTimeToUnlock(uint256 tokenId_)

    _checkDelegateeExist(address delegatee_)

    Events

    Errors

    Summary

    uint256 private constant EPOCH_DURATION = 1 weeks;
    uint256 private constant PRECISION = 100_000;
    constructor() {
        _disableInitializers();
    }
    function initialize(
        address owner_,
        IERC20 eywa_,
        ICollection collection_,
        IEmissionManagerV1 emissionManager_,
        IEscrowManagerExtended escrowManager_,
        IEscrowVoteManagerV1 escrowVoteManager_,
        ILockHolderFactoryV1 lockHolderFactory_,
        IRebaseRewardsDistributorV2 rebaseRewardsDistributor_,
        IDelegationConditionValidatorV1 delegationConditionValidator_
    ) external initializer;
    function setAssuranceLockParameters(
        uint256 minLockEywa_,
        uint256 minLockDuration_
    ) external onlyOwner;
    -   `minLockEywa_`: The minimum number of EYWA tokens that must be in the assurance lock.
    -   `minLockDuration_`: The the minimum time before unlocking that a assurance lock should have.
    function setMinLockVeEywa(uint256 minLockVeEywa_) external onlyOwner;
    function setDelegationParameters(InputDelegationParameters memory delegationParameters_) external;
    function setDelegationVoteParameters(
        address[] calldata pools_,
        uint256[] calldata weights_
    ) external;
    function setAutoVotePermission(bool permission_) external;
    function boost(
        uint256 tokenId_,
        uint256[] calldata collectionTokenIds_
    ) external;
    function deboost(
        uint256 tokenId_,
        uint256[] calldata collectionTokenIds_
    ) external;
    function extend(
        uint256[] calldata tokenIds_,
        uint256[] calldata lockDurations_
    ) external;
    function withdrawDeposit(uint256 amount_) external;
    function claim() external;
    function delegate(
        address delegatee_,
        uint256[] calldata tokenIds_
    ) external;
    function paymentAndExtendDelegations(uint256[] calldata tokenIds_) external;
    function claimIncentives(uint256[] calldata tokenIds_) external;
    function revokeDelegations(uint256[] calldata tokenIds_) external;
    function recallDelegations(uint256[] calldata tokenIds_) external;
    function vote(
        uint256[] calldata tokenIds_,
        address[][] calldata pools_,
        uint256[][] calldata weights_
    ) external;
    function autoVote(
        address delegatee_,
        uint256[] calldata tokenIds_
    ) external;
    function reset(uint256[] calldata tokenIds_) external;
    function poke(uint256[] calldata tokenIds_) external;
    function isAvailableDelegate(
        address delegator_,
        address delegatee_,
        uint256[] calldata tokenIds_
    ) external view returns(bool);
    function getDelegationsParameters() external view returns(OutputDelegationParameters[] memory);
    function getDelegationsVoteParametersByDelegate(
        address delegatee_
    ) external view returns(address[] memory pools_, uint256[] memory weights_);
    function getDelegationsInfoByTokenIds(
        uint256[] calldata tokenIds_
    ) external view returns(DelegationInfo[] memory);
    function getDelegationInfoAndParametersByTokenId(
        uint256 tokenId_
    ) 
        external
        view 
        returns(DelegationInfo memory delegationInfo_, DelegationParameters memory delegationParameters_);
    function getLockIdsByDelegator(address delegator_) external view returns(uint256[] memory);
    function getLockIdsByDelegatee(address delegatee_) external view returns(uint256[] memory);
    function getAssuranceLockStatus(
        uint256 tokenId_,
        address delegatee_
    ) public view returns(bool);
    function _delegate(
        IEscrowManagerExtended escrowManager_,
        DelegationParameters memory delegationParameters_,
        uint256[] calldata tokenIds_,
        address delegatee_
    ) private;
    function _recallDelegation(
        address delegator_,
        address delegatee_,
        uint256 tokenId_
    ) internal;
    function _getVotes(
        IEscrowManagerExtended escrowManager_,
        uint256[] calldata tokenIds_
    ) private view returns(uint256);
    function _getLastEpochOfDelegation(
        uint256 timeExpiry_,
        uint256 delegationEnd_
    ) internal view returns (uint256);
    function _getLastEpochOfDelegation(
        uint256 timeExpiry_,
        uint256 delegationEnd_,
        uint256 currentEpochStart_
    ) internal view returns (uint256);
    function _checkDelegationPaid(
        bool isSelfDelegation_,
        uint256 lastPaidEpoch_,
        uint256 paidEpoch_
    ) internal view returns (uint256);
    function _checkRewardsClaimed(
        uint256 tokenId_,
        uint256 currentEpochStart_,
        address lockHolder_
    ) internal view returns (uint256);
    _checkCaller(address caller_) internal view;
    function _checkDelegatorOrDelegatee(
        address delegator_,
        address delegatee_
    ) internal view;
    function _checkTimeExpiry(uint256 timeExpiry_) internal view
    function _checkLockHolder(
        address delegator_,
        address delegatee_
    ) internal view returns(address);
    function _checkAssuranceLock(
        uint256 assuranceLock_,
        address delegatee_
    ) internal view returns(address);
    function _checkDelegation(
        DelegationInfo memory delegationInfo_,
        address caller_,
        uint256 currentEpochStart_
    ) internal view returns(address);
    function _checkForSelfDelegation(uint256 tokenId_) internal view returns(address);
    function _currentEpochStart() internal view returns (uint256);
    function _nextEpochStart() internal view returns (uint256);
    function _getTimeToUnlock(uint256 tokenId_) internal view returns(uint256);
    function _checkDelegateeExist(address delegatee_) internal view;
    Mode B -- Sponsored / custom paymaster: your own verifying paymaster sponsors gas.
  • Mode C -- Native gas: no paymaster; the smart wallet pays gas in the native token directly.

  • Mode D -- Calldata only: raw calldata returned; integrator builds their own UserOperation and manages approvals.

  • The smart wallet address (from) must already be deployed on the source chain. If the contract is not deployed, the server returns a 400 NOT_SMART_ACCOUNT error.

    The request body uses the same base fields as EOA (from, recipient, routing) plus these AA-specific fields:

    Field
    Type
    Required
    Description

    walletType

    string

    Yes

    "4337"

    gasToken

    Do not include buildCalldata -- it is ignored for AA wallets.

    Gas is paid in an ERC-20 token through CrossCurve's Pimlico paymaster. The response includes a pimlicoChainName used to route subsequent bundler and paymaster calls through the /pimlico/{chainName} proxy endpoint.

    Request:

    Response:

    Response fields:

    Field
    Type
    Description

    walletType

    "4337"

    Wallet type echo

    calls

    array

    Ordered calls for the UserOperation (see below)

    Each item in calls has:

    Field
    Type
    Description

    to

    string

    Target contract address

    value

    string

    Native token value (wei)

    The three calls in order:

    1. Paymaster token approve -- approves the paymaster to spend the gas token.

    2. Router token approve -- approves the router to spend the input token.

    3. Router start -- calls router.start() to initiate the swap.

    Full flow (10 steps):

    1. POST /routing/scan/stream -- find a route (see EOA Step 2).

    2. POST /tx/create with walletType: "4337" and gasToken -- receive calls, pimlicoChainName, paymasterContext, paymasterAddress, entryPoint.

    3. POST /pimlico/{pimlicoChainName} -- call pimlico_getUserOperationGasPrice to get gas prices.

    4. Build a UserOperation from calls. Set maxFeePerGas and maxPriorityFeePerGas from step 3.

    5. POST /pimlico/{pimlicoChainName} -- call pm_getPaymasterStubData to get stub data for gas estimation.

    6. POST /pimlico/{pimlicoChainName} -- call eth_estimateUserOperationGas to fill gas limits.

    7. POST /pimlico/{pimlicoChainName} -- call pm_getPaymasterData to get final paymaster data.

    8. Sign the UserOperation.

    9. POST /pimlico/{pimlicoChainName} -- call eth_sendUserOperation to submit.

    10. Poll with eth_getUserOperationReceipt via POST /pimlico/{pimlicoChainName} until the operation is confirmed.

    Full Example (JavaScript)

    Full Example (TypeScript + permissionless)

    Your own verifying paymaster sponsors gas. No gasToken is needed.

    Request:

    Response:

    Key differences from Mode A:

    • 2 calls instead of 3 -- no paymaster token approve (your paymaster sponsors gas).

    • pimlicoChainName is absent -- the Pimlico proxy is not needed.

    • paymasterContext.token is the zero address.

    • The integrator manages their own paymaster and bundler infrastructure.

    Example (JavaScript)

    No paymaster is used. The smart wallet pays gas in the native token directly, the same way an EOA would.

    Request:

    Response:

    Key differences:

    • 2 calls -- router approve and router start.

    • value on the router start call may be non-zero.

    • pimlicoChainName, paymasterAddress, and entryPoint are absent.

    • paymasterContext.token is the zero address.

    • No paymaster is involved -- the smart wallet pays gas in the native token.

    Estimate gas and submit the UserOperation through your own bundler or node.

    For integrators with their own AA infrastructure who want raw calldata without the calls[] wrapper. The integrator builds their own approve calls, UserOperation, and paymaster interactions.

    Request:

    Response:

    Response fields:

    Field
    Type
    Description

    calldataOnly

    true

    Indicates calldata-only mode

    to

    string

    Router contract address

    The integrator is responsible for:

    • Building approve calls (if feeToken is an ERC-20, approve the router for amountIn + executionPrice).

    • Constructing the full UserOperation.

    • Managing paymaster interactions (if any).

    • Submitting through their own bundler.


    For EOA wallets with EIP-7702 code delegation. The EOA temporarily gains smart account functionality for the duration of the operation, without needing a separate smart wallet contract.

    Key differences from ERC-4337:

    • walletType is "7702" instead of "4337".

    • The sender address in the UserOperation is the EOA itself, not a separate smart account.

    • Requires an EIP-7702 authorization signature for code delegation.

    • Uses EntryPoint v0.8 (ERC-4337 uses v0.6).

    The same gas payment modes are available as ERC-4337: ERC-20 paymaster, sponsored/custom paymaster, and native gas. The response shape is identical -- see the ERC-4337 response fields for field descriptions.

    The request body uses the same fields as ERC-4337 with walletType set to "7702".

    ERC-20 paymaster mode:

    Native gas mode (no paymaster):

    Same shape as ERC-4337 but with walletType: "7702":

    1. POST /routing/scan/stream -- find a route (see EOA Step 2).

    2. POST /tx/create with walletType: "7702" and gasToken -- receive calls, pimlicoChainName, paymasterContext, paymasterAddress, entryPoint.

    3. POST /pimlico/{pimlicoChainName} -- call pimlico_getUserOperationGasPrice to get gas prices.

    4. Sign an EIP-7702 authorization for code delegation to the Smart7702 implementation.

    5. Build a UserOperation with the authorization. Set maxFeePerGas and maxPriorityFeePerGas from step 3.

    6. POST /pimlico/{pimlicoChainName} -- call pm_getPaymasterStubData to get stub data for gas estimation.

    7. POST /pimlico/{pimlicoChainName} -- call eth_estimateUserOperationGas to fill gas limits.

    8. POST /pimlico/{pimlicoChainName} -- call pm_getPaymasterData to get final paymaster data.

    9. Sign and send the UserOperation via POST /pimlico/{pimlicoChainName} using eth_sendUserOperation.

    1. POST /routing/scan/stream -- find a route (see EOA Step 2).

    2. POST /tx/create with walletType: "7702" (no gasToken) -- receive calls.

    3. Sign an EIP-7702 authorization for code delegation.

    4. Build a UserOperation from calls.

    5. Estimate gas, sign, and send. No paymaster is needed -- the EOA pays gas in the native token.

    This example shows the 7702-specific authorization step. See the ERC-4337 example for the pimlicoRpc helper and common patterns.


    JSON-RPC 2.0 proxy for account abstraction bundler and paymaster operations. Routes requests to the Pimlico infrastructure through the CrossCurve API.

    {chainName} is the chain identifier from the pimlicoChainName field in the /tx/create response (e.g. sepolia, sonic-testnet).

    Headers:

    Header
    Value

    Content-Type

    application/json

    api-key

    YOUR_API_KEY

    Method
    Description

    eth_sendUserOperation

    Submit a UserOperation

    eth_estimateUserOperationGas

    Estimate gas for a UserOperation

    eth_getUserOperationReceipt

    Get receipt by UserOperation hash

    Any method not in this list returns a 400 error.

    Constraint
    Value

    Rate limit

    60 requests per minute per IP

    Max payload

    50 KB

    Timeout

    15 seconds

    For eth_sendUserOperation and eth_estimateUserOperationGas, the EntryPoint address passed in params[1] must match one of the EntryPoint addresses configured for the chain.


    {
      "from": "0xSMART_WALLET_ADDRESS",
      "recipient": "0xRECIPIENT_ADDRESS",
      "routing": { },
      "walletType": "4337",
      "gasToken": "0xERC20_TOKEN_FOR_GAS"
    }
    {
      "walletType": "4337",
      "calls": [
        { "to": "0xGAS_TOKEN", "value": "0", "data": "0x..." },
        { "to": "0xTOKEN_IN", "value": "0", "data": "0x..." },
        { "to": "0xROUTER", "value": "0", "data": "0x..." }
      ],
      "chainId": 11155111,
      "pimlicoChainName": "sepolia",
      "paymasterContext": { "token": "0xGAS_TOKEN_ADDRESS" },
      "paymasterAddress": "0x...",
      "entryPoint": "0x..."
    }
    const API = "https://api.crosscurve.fi";
    const API_KEY = "YOUR_API_KEY";
    
    const SMART_WALLET = "0xSMART_WALLET_ADDRESS";
    const TOKEN_IN = "0xTOKEN_IN";
    const TOKEN_OUT = "0xTOKEN_OUT";
    const GAS_TOKEN = "0xGAS_TOKEN";
    const CHAIN_ID_IN = 11155111;
    const CHAIN_ID_OUT = 64165;
    const AMOUNT_IN = "1000000";
    
    // Step 1: Find a route (scanRoutes helper defined in EOA example above)
    const routes = await scanRoutes({
      from: SMART_WALLET,
      recipient: SMART_WALLET,
      params: {
        tokenIn: TOKEN_IN,
        amountIn: AMOUNT_IN,
        chainIdIn: CHAIN_ID_IN,
        tokenOut: TOKEN_OUT,
        chainIdOut: CHAIN_ID_OUT,
      },
      slippage: 1,
    });
    routes.sort((a, b) => {
      if (BigInt(a.amountOut) > BigInt(b.amountOut)) return -1;
      if (BigInt(a.amountOut) < BigInt(b.amountOut)) return 1;
      return 0;
    });
    const route = routes[0];
    
    // Step 2: Build AA transaction
    const txRes = await fetch(`${API}/tx/create`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        from: SMART_WALLET,
        recipient: SMART_WALLET,
        routing: route,
        walletType: "4337",
        gasToken: GAS_TOKEN,
      }),
    });
    const txData = await txRes.json();
    // txData = { walletType, calls, chainId, pimlicoChainName, paymasterContext, paymasterAddress, entryPoint }
    
    const { calls, pimlicoChainName, paymasterContext, entryPoint } = txData;
    
    // Helper: call Pimlico proxy
    async function pimlicoRpc(chainName, method, params) {
      const res = await fetch(`${API}/pimlico/${chainName}`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "api-key": API_KEY,
        },
        body: JSON.stringify({ jsonrpc: "2.0", method, params, id: 1 }),
      });
      const json = await res.json();
      if (json.error) throw new Error(json.error.message);
      return json.result;
    }
    
    // Step 3: Get gas prices
    const gasPrice = await pimlicoRpc(pimlicoChainName, "pimlico_getUserOperationGasPrice", []);
    
    // Step 4: Build UserOperation
    const userOp = {
      sender: SMART_WALLET,
      nonce: await getNonce(SMART_WALLET, entryPoint), // from your smart account
      callData: encodeMulticall(calls), // encode calls into a single callData
      callGasLimit: "0x0",
      verificationGasLimit: "0x0",
      preVerificationGas: "0x0",
      maxFeePerGas: gasPrice.standard.maxFeePerGas,
      maxPriorityFeePerGas: gasPrice.standard.maxPriorityFeePerGas,
      signature: "0x", // empty signature for estimation
    };
    
    // Step 5: Get paymaster stub data
    const stubData = await pimlicoRpc(pimlicoChainName, "pm_getPaymasterStubData", [
      userOp,
      entryPoint,
      pimlicoChainName,
      { token: paymasterContext.token },
    ]);
    userOp.paymasterAndData = stubData.paymasterAndData;
    
    // Step 6: Estimate gas
    const gasEstimate = await pimlicoRpc(
      pimlicoChainName,
      "eth_estimateUserOperationGas",
      [userOp, entryPoint]
    );
    userOp.callGasLimit = gasEstimate.callGasLimit;
    userOp.verificationGasLimit = gasEstimate.verificationGasLimit;
    userOp.preVerificationGas = gasEstimate.preVerificationGas;
    
    // Step 7: Get final paymaster data
    const pmData = await pimlicoRpc(pimlicoChainName, "pm_getPaymasterData", [
      userOp,
      entryPoint,
      pimlicoChainName,
      { token: paymasterContext.token },
    ]);
    userOp.paymasterAndData = pmData.paymasterAndData;
    
    // Step 8: Sign
    userOp.signature = await signUserOp(userOp, entryPoint, txData.chainId);
    
    // Step 9: Send
    const userOpHash = await pimlicoRpc(
      pimlicoChainName,
      "eth_sendUserOperation",
      [userOp, entryPoint]
    );
    console.log("UserOperation hash:", userOpHash);
    
    // Step 10: Poll for receipt
    async function pollUserOp(hash) {
      while (true) {
        const receipt = await pimlicoRpc(
          pimlicoChainName,
          "eth_getUserOperationReceipt",
          [hash]
        );
        if (receipt) return receipt;
        await new Promise((r) => setTimeout(r, 5000));
      }
    }
    
    const receipt = await pollUserOp(userOpHash);
    console.log("UserOperation confirmed:", receipt.receipt.transactionHash);
    import { createPublicClient, http } from "viem";
    import { sepolia } from "viem/chains";
    import {
      createSmartAccountClient,
      type SmartAccountClient,
    } from "permissionless";
    import { createPimlicoClient } from "permissionless/clients/pimlico";
    
    const API = "https://api.crosscurve.fi";
    const API_KEY = "YOUR_API_KEY";
    
    const SMART_WALLET = "0xSMART_WALLET_ADDRESS" as `0x${string}`;
    const TOKEN_IN = "0xTOKEN_IN" as `0x${string}`;
    const TOKEN_OUT = "0xTOKEN_OUT" as `0x${string}`;
    const GAS_TOKEN = "0xGAS_TOKEN" as `0x${string}`;
    const CHAIN_ID_IN = 11155111;
    const CHAIN_ID_OUT = 64165;
    const AMOUNT_IN = "1000000";
    
    interface AACall {
      to: string;
      value: string;
      data: string;
    }
    
    interface PaymasterContext {
      token: string;
    }
    
    interface CreateTx4337Response {
      walletType: "4337";
      calls: AACall[];
      chainId: number;
      pimlicoChainName?: string;
      paymasterContext: PaymasterContext;
      paymasterAddress?: string;
      entryPoint?: string;
    }
    
    // Step 1: Find a route (scanRoutes helper defined in EOA example above)
    const routes = await scanRoutes({
      from: SMART_WALLET,
      recipient: SMART_WALLET,
      params: {
        tokenIn: TOKEN_IN,
        amountIn: AMOUNT_IN,
        chainIdIn: CHAIN_ID_IN,
        tokenOut: TOKEN_OUT,
        chainIdOut: CHAIN_ID_OUT,
      },
      slippage: 1,
    });
    routes.sort((a: any, b: any) => {
      if (BigInt(a.amountOut) > BigInt(b.amountOut)) return -1;
      if (BigInt(a.amountOut) < BigInt(b.amountOut)) return 1;
      return 0;
    });
    const route = routes[0];
    
    // Step 2: Build AA transaction
    const txRes = await fetch(`${API}/tx/create`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        from: SMART_WALLET,
        recipient: SMART_WALLET,
        routing: route,
        walletType: "4337",
        gasToken: GAS_TOKEN,
      }),
    });
    const txData: CreateTx4337Response = await txRes.json();
    
    const { calls, pimlicoChainName, paymasterContext, entryPoint } = txData;
    
    // Create a Pimlico client that routes through the CrossCurve proxy
    const pimlicoClient = createPimlicoClient({
      chain: sepolia,
      transport: http(`${API}/pimlico/${pimlicoChainName}`, {
        fetchOptions: {
          headers: { "api-key": API_KEY },
        },
      }),
      entryPoint: {
        address: entryPoint as `0x${string}`,
        version: "0.7",
      },
    });
    
    // Create your smart account client (implementation depends on your account type)
    // For example, with a Safe, Kernel, or other account:
    const smartAccountClient: SmartAccountClient = createSmartAccountClient({
      account: yourSmartAccount, // your account implementation
      chain: sepolia,
      bundlerTransport: http(`${API}/pimlico/${pimlicoChainName}`, {
        fetchOptions: {
          headers: { "api-key": API_KEY },
        },
      }),
      paymaster: pimlicoClient,
      paymasterContext: { token: paymasterContext.token },
    });
    
    // Step 3: Send the UserOperation
    const userOpHash = await smartAccountClient.sendUserOperation({
      calls: calls.map((call) => ({
        to: call.to as `0x${string}`,
        value: BigInt(call.value),
        data: call.data as `0x${string}`,
      })),
    });
    
    console.log("UserOperation hash:", userOpHash);
    
    // Step 4: Wait for receipt
    const receipt = await smartAccountClient.waitForUserOperationReceipt({
      hash: userOpHash,
    });
    
    console.log("Confirmed:", receipt.receipt.transactionHash);
    {
      "from": "0xSMART_WALLET_ADDRESS",
      "recipient": "0xRECIPIENT_ADDRESS",
      "routing": { },
      "walletType": "4337",
      "paymasterAddress": "0xYOUR_VERIFYING_PAYMASTER",
      "entryPoint": "0xENTRYPOINT"
    }
    {
      "walletType": "4337",
      "calls": [
        { "to": "0xTOKEN_IN", "value": "0", "data": "0x..." },
        { "to": "0xROUTER", "value": "0", "data": "0x..." }
      ],
      "chainId": 11155111,
      "paymasterContext": { "token": "0x0000000000000000000000000000000000000000" },
      "paymasterAddress": "0xYOUR_VERIFYING_PAYMASTER",
      "entryPoint": "0x..."
    }
    const API = "https://api.crosscurve.fi";
    const SMART_WALLET = "0xSMART_WALLET_ADDRESS";
    
    // After obtaining a route from /routing/scan/stream (see EOA example)...
    
    const txRes = await fetch(`${API}/tx/create`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        from: SMART_WALLET,
        recipient: SMART_WALLET,
        routing: route,
        walletType: "4337",
        paymasterAddress: "0xYOUR_VERIFYING_PAYMASTER",
        entryPoint: "0xENTRYPOINT",
      }),
    });
    const txData = await txRes.json();
    // txData = { walletType, calls, chainId, paymasterContext, paymasterAddress, entryPoint }
    
    // Build UserOperation from txData.calls
    const userOp = {
      sender: SMART_WALLET,
      nonce: await getNonce(SMART_WALLET, txData.entryPoint),
      callData: encodeMulticall(txData.calls),
      // ... fill gas fields via your bundler
    };
    
    // Use your own paymaster to sponsor and sign the UserOperation
    // Use your own bundler to estimate gas and submit
    const userOpHash = await yourBundler.sendUserOperation(userOp, txData.entryPoint);
    {
      "from": "0xSMART_WALLET_ADDRESS",
      "recipient": "0xRECIPIENT_ADDRESS",
      "routing": { },
      "walletType": "4337"
    }
    {
      "walletType": "4337",
      "calls": [
        { "to": "0xTOKEN_IN", "value": "0", "data": "0x..." },
        { "to": "0xROUTER", "value": "1234567", "data": "0x..." }
      ],
      "chainId": 11155111,
      "paymasterContext": { "token": "0x0000000000000000000000000000000000000000" }
    }
    {
      "from": "0xSMART_WALLET_ADDRESS",
      "recipient": "0xRECIPIENT_ADDRESS",
      "routing": { },
      "walletType": "4337",
      "calldataOnly": true
    }
    {
      "calldataOnly": true,
      "to": "0xROUTER",
      "data": "0x...",
      "value": "0",
      "feeToken": "0x...",
      "executionPrice": "...",
      "chainId": 11155111
    }
    {
      "from": "0xYOUR_EOA",
      "recipient": "0xRECIPIENT",
      "routing": { },
      "walletType": "7702",
      "gasToken": "0xGAS_TOKEN"
    }
    {
      "from": "0xYOUR_EOA",
      "recipient": "0xRECIPIENT",
      "routing": { },
      "walletType": "7702"
    }
    {
      "walletType": "7702",
      "calls": [
        { "to": "0xTOKEN_ADDRESS", "value": "0", "data": "0xAPPROVE_CALLDATA" },
        { "to": "0xROUTER_ADDRESS", "value": "0", "data": "0xSTART_CALLDATA" }
      ],
      "chainId": 11155111,
      "pimlicoChainName": "sepolia",
      "paymasterContext": { "token": "0xERC20_GAS_TOKEN" },
      "paymasterAddress": "0x...",
      "entryPoint": "0x..."
    }
    const API = "https://api.crosscurve.fi";
    const API_KEY = "YOUR_API_KEY";
    
    const EOA_ADDRESS = "0xYOUR_EOA";
    const TOKEN_IN = "0xTOKEN_IN";
    const TOKEN_OUT = "0xTOKEN_OUT";
    const GAS_TOKEN = "0xGAS_TOKEN";
    const CHAIN_ID_IN = 11155111;
    const CHAIN_ID_OUT = 64165;
    const AMOUNT_IN = "1000000";
    
    // Helper: call Pimlico proxy (same as ERC-4337 example)
    async function pimlicoRpc(chainName, method, params) {
      const res = await fetch(`${API}/pimlico/${chainName}`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "api-key": API_KEY,
        },
        body: JSON.stringify({ jsonrpc: "2.0", method, params, id: 1 }),
      });
      const json = await res.json();
      if (json.error) throw new Error(json.error.message);
      return json.result;
    }
    
    // Step 1: Find a route (scanRoutes helper defined in EOA example above)
    const routes = await scanRoutes({
      from: EOA_ADDRESS,
      recipient: EOA_ADDRESS,
      params: {
        tokenIn: TOKEN_IN,
        amountIn: AMOUNT_IN,
        chainIdIn: CHAIN_ID_IN,
        tokenOut: TOKEN_OUT,
        chainIdOut: CHAIN_ID_OUT,
      },
      slippage: 1,
    });
    routes.sort((a, b) => {
      if (BigInt(a.amountOut) > BigInt(b.amountOut)) return -1;
      if (BigInt(a.amountOut) < BigInt(b.amountOut)) return 1;
      return 0;
    });
    const route = routes[0];
    
    // Step 2: Build AA transaction with 7702
    const txRes = await fetch(`${API}/tx/create`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        from: EOA_ADDRESS,
        recipient: EOA_ADDRESS,
        routing: route,
        walletType: "7702",
        gasToken: GAS_TOKEN,
      }),
    });
    const txData = await txRes.json();
    
    const { calls, pimlicoChainName, paymasterContext, entryPoint } = txData;
    
    // Step 3: Get gas prices
    const gasPrice = await pimlicoRpc(pimlicoChainName, "pimlico_getUserOperationGasPrice", []);
    
    // Step 4: Sign EIP-7702 authorization for code delegation
    const authorization = await walletClient.signAuthorization({
      contractAddress: SMART_7702_IMPLEMENTATION, // delegation target
      chainId: txData.chainId,
    });
    
    // Step 5: Build UserOperation with authorization
    const userOp = {
      sender: EOA_ADDRESS,
      nonce: await getNonce(EOA_ADDRESS, entryPoint),
      callData: encodeMulticall(calls),
      callGasLimit: "0x0",
      verificationGasLimit: "0x0",
      preVerificationGas: "0x0",
      maxFeePerGas: gasPrice.standard.maxFeePerGas,
      maxPriorityFeePerGas: gasPrice.standard.maxPriorityFeePerGas,
      authorization, // EIP-7702 authorization
      signature: "0x",
    };
    
    // Step 6: Get paymaster stub data
    const stubData = await pimlicoRpc(pimlicoChainName, "pm_getPaymasterStubData", [
      userOp,
      entryPoint,
      pimlicoChainName,
      { token: paymasterContext.token },
    ]);
    userOp.paymasterAndData = stubData.paymasterAndData;
    
    // Step 7: Estimate gas
    const gasEstimate = await pimlicoRpc(
      pimlicoChainName,
      "eth_estimateUserOperationGas",
      [userOp, entryPoint]
    );
    userOp.callGasLimit = gasEstimate.callGasLimit;
    userOp.verificationGasLimit = gasEstimate.verificationGasLimit;
    userOp.preVerificationGas = gasEstimate.preVerificationGas;
    
    // Step 8: Get final paymaster data
    const pmData = await pimlicoRpc(pimlicoChainName, "pm_getPaymasterData", [
      userOp,
      entryPoint,
      pimlicoChainName,
      { token: paymasterContext.token },
    ]);
    userOp.paymasterAndData = pmData.paymasterAndData;
    
    // Step 9: Sign and send
    userOp.signature = await signUserOp(userOp, entryPoint, txData.chainId);
    
    const userOpHash = await pimlicoRpc(
      pimlicoChainName,
      "eth_sendUserOperation",
      [userOp, entryPoint]
    );
    console.log("UserOperation hash:", userOpHash);
    POST /pimlico/{chainName}
    {
      "jsonrpc": "2.0",
      "id": 1,
      "method": "METHOD_NAME",
      "params": [...]
    }
    const API = "https://api.crosscurve.fi";
    const API_KEY = "YOUR_API_KEY";
    
    async function pimlicoRpc(chainName, method, params) {
      const res = await fetch(`${API}/pimlico/${chainName}`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "api-key": API_KEY,
        },
        body: JSON.stringify({
          jsonrpc: "2.0",
          id: 1,
          method,
          params,
        }),
      });
      const json = await res.json();
      if (json.error) throw new Error(json.error.message);
      return json.result;
    }
    
    // Usage: get gas prices
    const gasPrice = await pimlicoRpc("sepolia", "pimlico_getUserOperationGasPrice", []);
    
    // Usage: estimate gas for a UserOperation
    const gasEstimate = await pimlicoRpc("sepolia", "eth_estimateUserOperationGas", [
      userOp,
      "0xENTRYPOINT_ADDRESS",
    ]);

    Request Fields

    Mode A -- ERC-20 Paymaster

    Mode B -- Sponsored / Custom Paymaster

    Mode C -- Native Gas

    Mode D -- Calldata Only

    EIP-7702 Swap

    Request

    Response

    Full Flow (ERC-20 Paymaster)

    Full Flow (Native Gas)

    Full Example (JavaScript, ERC-20 Paymaster)

    Pimlico Proxy

    Request Format

    Allowed Methods

    Limits

    Example -- Reusable Helper (JavaScript)

    string

    No

    ERC-20 token address for gas payment via paymaster

    paymasterAddress

    string

    No

    Custom paymaster contract address

    entryPoint

    string

    No

    Custom EntryPoint contract address

    calldataOnly

    boolean

    No

    Return raw calldata without calls[] wrapper

    chainId

    number

    Source chain ID

    pimlicoChainName

    string

    Chain name for the /pimlico/{chainName} proxy

    paymasterContext

    object

    Contains token -- the ERC-20 address used for gas payment

    paymasterAddress

    string

    Paymaster contract address (present in ERC-20 and sponsored modes)

    entryPoint

    string

    EntryPoint contract address (present in ERC-20 and sponsored modes)

    data

    string

    Encoded calldata

    data

    string

    Encoded calldata for router.start()

    value

    string

    Native token value (wei)

    feeToken

    string

    Token address for fee payment (zero address for native token)

    executionPrice

    string

    Delivery fee amount in feeToken units

    chainId

    number

    Source chain ID

    eth_getUserOperationByHash

    Get UserOperation by hash

    eth_supportedEntryPoints

    List supported EntryPoint addresses

    pm_getPaymasterData

    Get paymaster data for gas sponsoring

    pm_getPaymasterStubData

    Get stub data for gas estimation

    pm_supportedTokens

    List tokens available for gas payment

    pimlico_getUserOperationGasPrice

    Get recommended gas prices

    pimlico_getTokenQuotes

    Get token quotes for paymaster

    Batch JSON-RPC

    Not supported

    CrossCurve smart contracts

    ss-chain liquidity protocol smart contracts (CrossCurve) are a type of self-executing digital agreement stored on a blockchain that automatically execute when predetermined terms and conditions are met. These contracts facilitate the creation of liquidity pools that enable decentralized trading, offering behaviors that are more predictable and in line with the primary principles of blockchain technology, such as trustless operations without susceptible governance. In general, smart contracts are designed to digitally facilitate, verify, or enforce the negotiation or performance of a contract. They allow transactions to be conducted without the need for intermediaries, while ensuring that these transactions are trackable and irreversible once completed.

    Chain\Name
    AddressBook
    PortalV2
    SynthesisV2
    SynthFactory
    UnifiedRouterV2
    OpsRegistrar
    Whitelist
    FeesTreasury
    VirtualPriceSender
    VirtualPriceReceiver
    VirtualPriceReceiver
    VirtualPriceReceiver
    VirtualPriceReceiverV2
    VirtualPriceReceiver3
    VirtualPriceReceiver4
    Locker
    Chain\Name
    Adapter (stable1)
    Adapter (stable1)
    Adapter (stable2)
    Adapter (stable2)
    Adapter (stable2)
    Adapter (stable3)
    Adapter (stable4)
    Adapter (crypto1)
    Adapter (crypto1)
    Adapter (crypto4)
    Adapter (crypto4)

    BSC

    Polygon

    Avalanche

    Optimism

    Arbitrum

    Fantom

    Base

    Gnosis

    Mantle

    Blast

    Linea

    Taiko

    Unit0

    Celo

    Fraxtal

    Kava

    Metis

    Mode

    Sonic

    Manta

    Description

    same as v1.5

    same as v1.5

    same as v1.5

    v 2.51 (celo)

    same as v1

    same as v1

    same as v2

    xCRVUSDC

    x3CRYPTO

    Adapter (crypto5)
    Adapter (crypto6)
    Adapter (crypto7)
    Adapter (meta1)

    Ethereum

    Ethereum

    link

    link

    link

    link

    link

    link

    link

    link

    link

    n: 2

    zap

    link

    link

    link

    link

    link

    link

    xCRVUSDT

    xSTABLE

    xBTC

    xSTABLE2

    BNB

    link

    Polygon

    link

    link

    link

    Avalanche

    link

    link

    link

    link

    Optimism

    link

    link

    link

    link

    Arbitrum

    link

    link

    link

    link

    link

    Fantom

    link

    link

    Base

    link

    link

    Gnosis

    link

    LP

    link

    Taiko

    link

    link

    Celo

    link

    Fraxtal

    link

    link

    Sonic

    link

    link

    Description

    n: 3

    n: 3

    n: 2

    n: 3

    n: 4

    Aave, n: 3

    stableNG/cryptoNG

    n: 3

    n: 2

    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    link
    LP
    link
    link
    link
    link

    link
    link
    link
    link
    link

    Supported tokens

    Assets available for cross-chain swaps

    Assets

    Chain
    Ticker/Link
    Address

    Ethereum

    0x8cb8C4263EB26b2349d74ea2cB1B27bc40709e12

    Ethereum

    Chain
    Ticker/Link
    Address

    Ethereum

    0x390f3595bCa2Df7d23783dFd126427CCeb997BF4

    Ethereum

    0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490

    Ethereum

    0xb7ecb2aa52aa64a717180e030241bc75cd946726

    Arbitrum

    0x82670f35306253222f8a165869b28c64739ac62e

    Arbitrum

    0xec090cf6DD891D2d014beA6edAda6e05E025D93d

    Arbitrum

    0x73aF1150F265419Ef8a5DB41908B700C32D49135

    Arbitrum

    0x7f90122BF0700F9E7e1F688fe926940E8839F353

    Arbitrum

    0x186cf879186986a20aadfb7ead50e3c20cb26cec

    Arbitrum

    0xdadd23929ca8efcbc43aaf8f677d426563cc40d7

    Arbitrum

    0x6579758e9e85434450d638cfbea0f2fe79856dda

    Polygon

    0xdAD97F7713Ae9437fa9249920eC8507e5FbB23d3

    Polygon

    0xb0658482b405496c4ee9453cd0a463b134aef9d0

    Polygon

    0x5225010A0AE133B357861782B0B865a48471b2C5

    Polygon

    0xA70Af99bFF6b168327f9D1480e29173e757c7904

    Polygon

    0xE7a24EF0C5e95Ffb0f6684b813A78F2a3AD7D171

    Polygon

    0xA73EdCf18421B56D9AF1cE08A34E102E23b2C4B6

    Avalanche

    0x1daB6560494B04473A0BE3E7D83CF3Fdf3a51828

    Avalanche

    0x1dc5c0f8668a9f54ed922171d578011850ca0341

    Avalanche

    0x1337BedC9D22ecbe766dF105c9623922A27963EC

    Optimism

    0x03771e24b7C9172d163Bf447490B142a15be3485

    Optimism

    0x4456d13Fc6736e8e8330394c0C622103E06ea419

    Optimism

    0xD1b30BA128573fcd7D141C8A987961b40e047BB6

    Optimism

    0x1337BedC9D22ecbe766dF105c9623922A27963EC

    BNB chain

    0xC4Ec3aB41182E70cA45a764fFc5c45B9A82cCc97

    BNB chain

    0xAE87E5Fa20f335ce14AA3B9E0616308d9AC7d4Ce

    BNB chain

    0xA5E0E46462970C9Ee8C2ECadcde254c483748Ec4

    Base

    0x6e53131F68a034873b6bFA15502aF094Ef0c5854

    Base

    0xf6C5F01C7F3148891ad0e19DF78743D31E390D1f

    Gnosis

    0x1337BedC9D22ecbe766dF105c9623922A27963EC

    Gnosis

    0x7f90122BF0700F9E7e1F688fe926940E8839F353

    Celo

    0x28F209844029755FC563c1bD4FD21f42DC7CE0e4

    Fraxtal

    0xcAEF324bea3Ff5c7a08710081294F3344fFAdC54

    Fantom

    0x7d04f016749c215e52138b06bb35ee8491e739fd

    Fantom

    0x353bb1dfbc52bc3b0e7d264216b1455df00f50be

    Fantom

    0x5ecac5fb1d9634f9e1c2dab2381b9adaada5f80b

    Fantom

    0x3f833ed02629545dd78afc3d585f7f3918a3de62

    Fantom

    0xa3a63276b8668583e1b47b979d1093d9aaf431ee

    Fantom

    0x15ee0d5f92fd869c2fbf26ea785e9d150353568d

    Fantom

    0x3c2fcf53f742345c5c1b3dcb2612a1949bc1f18d

    Fantom

    0xabba40f628f055149f1c7415c4388363392279c3

    Fantom

    0x37F5dae6039C8eC4c32ad7D3e2a07aCaa55C08f9

    Fantom

    0x06a2e1521afde7f7dc30d351dcf04408042f536e

    Sonic

    0x38dd6b3c096c8cbe649fa0039cc144f333be8e61

    Sonic

    0xf1232a1ab5661abdd6e02c6d8ac9940a23bb0b84

    Sonic

    0x346704605c72d9f5f9f02d651e5a3dcce6964f3d

    Sonic

    0x4fe12cf68147e902f4ccd8a3d4c13e89fba92384

    Sonic

    0xf159c51297306839b7d44cbb5cb9360e4623ae5a

    Sonic

    0xdac15649b025ba0047718512111c34096e9545e8

    Sonic

    0xf821404ac19ac1786caca7e3e12658d72ece885e

    Sonic

    0x440bcab62d629ba60ca56b80e565636e0c404e60

    Sonic

    0xd9bf67d8a5d698a028160f62480d456801f0b4b1

    Sonic

    0x435a160ef111ad0aa0867bece7b85cb77dce3c8a

    Sonic

    0x90135d7300c690d786fa8fea071cd4c2ed080d16

    Sonic

    0x20c2e44bbbea698da4a4cb687514e66385996639

    Sonic

    0xedcf9ef9b389a8f52e81958d8212faf6fbd758ae

    Sonic

    0x6988d6eec3ca7d24c0358bab8018787117325c2b

    Sonic

    0x9e63e5d31fd0136290ef99b3cac4515f346fef1c

    Sonic

    0x2b0911095350785fb32a557d1d2e3b36a9bb9252

    Sonic

    0xaa186960df95495084ef1ddc40a3bdac22b0d343

    Sonic

    0xb7bb92ff0ec68e6d79a238174e42c12ff5ef2b00

    Sonic

    0x024cc841cd7fe4e7dd7253676c688146599923cf

    Sonic

    0x2e97cf8da26ce3858950dd85b8f69e39ebd251f5

    Sonic

    0x24479a0d48849781b4386ed91fdd84241673ab1e

    Sonic

    0x9ccaabd2610d467b1f76c8aacec4f567ec61d78e

    Sonic

    0x424757a5169e1f3b45436c9b2e5421dc39dc4897

    Sonic

    0xa5a5da9c386855b199b8928cbb59c7ac6505ba89

    Sonic

    0x6f6522261f89d988d5f5caa5e4e658344517b114

    Sonic

    0x13882f7f207329db487ce99839c26392a233d97b

    Sonic

    0xeb427d3cc29ec4c49e48fccc580b11f15d7d096d

    Sonic

    0xdbb986d7fef61260c7f9a443e62e8a91974c5e3d

    Sonic

    0xa4948da3f2007193dd7404278fed15d48c617417

    Sonic

    0x8bb9b3e45fa6b4bf4bbb66ad09f485c5509a0e4c

    Sonic

    0x601538c805ea9d83a49c132f18417db9666f69d5

    Sonic

    0x759a32b417bb471da76cf41ca2ea42f4e0b143eb

    Sonic

    0xe5a0813a7de6abd8599594e84cb23e4a6d9d9800

    Sonic

    0x6d9f0ff2b7f1397ee731f6370d8e4699ffad7bc5

    Sonic

    0x1008358eecb59723391fba0f8a6b36c5346dab2d

    Sonic

    0x09679c768d17b52bfa059010475f9a0bdb0d6fea

    Sonic

    0x1c404afffba0e70426dc601aeaa6205eca8c9078

    Sonic

    0x7b823067ece11047f83f48647110e7a777e2bf5a

    Sonic

    0x538a5534543752d5abbc8cd11760f8be3625e7b1

    Sonic

    0xdb0a43327626c0e3e87ce936bc0cdf2ee9475c22

    Sonic

    0x5fa5168497db4ec1964b3208c18cb6157e5652e4

    Sonic

    0x1894a7203faa464f7afa3b8c319a3cac8beb6cda

    Sonic

    0xee05755051e8b1ccf85747a83d0ef8b00f161180

    Sonic

    0x9b78e02ddddda4117ddf6be8a0fbd15c45907895

    Sonic

    0x3301e4326cf2939cd6b8f23ddf7bc2a1713fd06a

    Taiko

    0xB391F2D5B83B3900997B4D6880ba7818Bef3591a

    rEYWA

    0x70980bD7253f8150dDD973CB430374Adaa0A143F

    Ethereum

    crvUSD

    0xf939e0a03fb07f59a73314e73794be0e57ac1b4e

    Ethereum

    USDC

    0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48

    Ethereum

    USDT

    0xdac17f958d2ee523a2206206994597c13d831ec7

    Ethereum

    DAI

    0x6b175474e89094c44da98b954eedeac495271d0f

    Ethereum

    USD0

    0x73a15fed60bf67631dc6cd7bc5b6e8da8190acf5

    Ethereum

    USD0++

    0x35d8949372d46b7a3d5a56006ae77b215fc69bc0

    Ethereum

    FRAX

    0x853d955acef822db058eb8505911ed77f175b99e

    Ethereum

    USDe

    0x4c9edd5852cd905f086c759e8383e09bff1e68b3

    Ethereum

    sDAI

    0x83f20f44975d03b1b09e64809b757c47f942beea

    Ethereum

    sUSDe

    0x9d39a5de30e57443bff2a8307a4256c8797a3497

    Ethereum

    cUSDO

    0xad55aebc9b8c03fc43cd9f62260391c13c23e7c0

    Ethereum

    USDL

    0xbdc7c08592ee4aa51d06c27ee23d5087d65adbcd

    Ethereum

    deUSD

    0x15700b564ca08d9439c58ca5053166e8317aa138

    Ethereum

    DOLA

    0x865377367054516e17014ccded1e7d814edc9ce4

    Ethereum

    PYUSD

    0x6c3ea9036406852006290770bedfcaba0e23a0e8

    Ethereum

    fxUSD

    0x085780639cc2cacd35e474e71f4d000e2405d8f6

    Ethereum

    GHO

    0x40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f

    Ethereum

    USR

    0x66a1e37c9b0eaddca17d3662d6c05f4decf3e110

    Ethereum

    CRV

    0xD533a949740bb3306d119CC777fa900bA034cd52

    Ethereum

    WBTC

    0x2260fac5e5542a773aa44fbcfedf7c193bc2c599

    Ethereum

    tBTC

    0x18084fbA666a33d37592fA2633fD49a74DD93a88

    Ethereum

    ETH

    native coin

    Ethereum

    WETH

    0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

    Arbitrum

    EYWA

    0x7A10F506E4c7658e6AD15Fdf0443d450B7FA80D7

    Arbitrum

    rEYWA

    0xD9879D9DbDc5042D8f1C2710Be293909B985dc90

    Arbitrum

    crvUSD

    0x498bf2b1e120fed3ad3d42ea2165e9b73f99c1e5

    Arbitrum

    USDC.e

    0xff970a61a04b1ca14834a43f5de4533ebddb5cc8

    Arbitrum

    USDC

    0xaf88d065e77c8cC2239327C5EDb3A432268e5831

    Arbitrum

    USDT

    0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9

    Arbitrum

    USDM

    0x59d9356e565ab3a36dd77763fc0d87feaf85508c

    Arbitrum

    eUSD

    0x12275dcb9048680c4be40942ea4d92c74c63b844

    Arbitrum

    CRV

    0x11cDb42B0EB46D95f990BeDD4695A6e3fA034978

    Arbitrum

    ARB

    0x912CE59144191C1204E64559FE8253a0e49E6548

    Arbitrum

    WBTC

    0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f

    Arbitrum

    tBTC

    0x6c84a8f1c29108F47a79964b5Fe888D4f4D0dE40

    Arbitrum

    IBTC

    0x050C24dBf1eEc17babE5fc585F06116A259CC77A

    Arbitrum

    ETH

    native coin

    Arbitrum

    WETH

    0x82af49447d8a07e3bd95bd0d56f35241523fbab1

    Arbitrum

    UNIT0

    0x21ab704b2cdf792e1e84f591ca082fff8de12198

    Arbitrum

    WUNIT0

    0xe80698d9c55d9212c4dae8bed00e1357d804c62a

    Arbitrum

    OGC

    0x21b1b07af26613479e526c058749239e460f8a2f

    Arbitrum

    xcmGEMS1

    0x432D9C4Cc7021dDcF6e1D2Af4886dd29d7709582

    Optimism

    crvUSD

    0xc52d7f23a2e460248db6ee192cb23dd12bddcbf6

    Optimism

    USDC.e

    0x7F5c764cBc14f9669B88837ca1490cCa17c31607

    Optimism

    USDT

    0x94b008aA00579c1307B0EF2c499aD98a8ce58e58

    Optimism

    DAI

    0xda10009cbd5d07dd0cecc66161fc93d7c9000da1

    Optimism

    CRV

    0x0994206dfe8de6ec6920ff4d779b0d950605fb53

    Optimism

    WBTC

    0x68f180fcCe6836688e9084f035309E29Bf0A2095

    Optimism

    tBTC

    0x6c84a8f1c29108F47a79964b5Fe888D4f4D0dE40

    Optimism

    ETH

    native coin

    Optimism

    WETH

    0x4200000000000000000000000000000000000006

    Optimism

    OGC

    0x21b1b07af26613479e526c058749239e460f8a2f

    Avalanche

    DAI.e

    0xd586e7f844cea2f87f50152665bcbc2c279d8d70

    Avalanche

    USDC.e

    0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664

    Avalanche

    USDT.e

    0xc7198437980c041c805a1edcba50c1ce5db95118

    Avalanche

    avDAI

    0x47afa96cdc9fab46904a55a6ad4bf6660b53c38a

    Avalanche

    avUSDC

    0x46a51127c3ce23fb7ab1de06226147f446e4a857

    Avalanche

    avUSDT

    0x532e6537fea298397212f09a61e03311686f548e

    Avalanche

    USDt

    0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7

    Avalanche

    YUSD

    0x111111111111ed1D73f860F57b2798b683f2d325

    Avalanche

    MIM

    0x130966628846BFd36ff31a822705796e8cb8C18D

    Avalanche

    BTC.b

    0x152b9d0FdC40C096757F570A51E494bd4b943E50

    Avalanche

    WETH.e

    0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB

    Polygon

    crvUSD

    0xc4ce1d6f5d98d65ee25cf85e9f2e9dcfee6cb5d6

    Polygon

    USDC.e

    0x2791bca1f2de4661ed88a30c99a7a9449aa84174

    Polygon

    amUSDC

    0x1a13f4ca1d028320a707d99520abfefca3998b7f

    Polygon

    USDT

    0xc2132d05d31c914a87c6611c10748aeb04b58e8f

    Polygon

    amUSDT

    0x60d55f02a771d515e077c9c2403a1ef324885cec

    Polygon

    DAI

    0x8f3cf7ad23cd3cadbd9735aff958023239c6a063

    Polygon

    amDAI

    0x27f8d03b3a2196956ed754badc28d73be8830a6e

    Polygon

    CRV

    0x172370d5cd63279efa6d502dab29171933a610af

    Polygon

    WBTC

    0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6

    Polygon

    WETH

    0x7ceb23fd6bc0add59e62ac25578270cff1b9f619

    Polygon

    OGC

    0x21b1b07af26613479e526c058749239e460f8a2f

    BSC

    EYWA

    0x7A10F506E4c7658e6AD15Fdf0443d450B7FA80D7

    BSC

    crvUSD

    0xe2fb3f127f5450dee44afe054385d74c392bdef4

    BSC

    FDUSD

    0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409

    BSC

    USDC

    0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d

    BSC

    USDT

    0x55d398326f99059fF775485246999027B3197955

    BSC

    USDX

    0xf3527ef8dE265eAa3716FB312c12847bFBA66Cef

    BSC

    sUSDX

    0x7788A3538C5fc7F9c7C8A74EAC4c898fC8d87d92

    BSC

    BTCB

    0x7130d2a12b9bcbfae4f2634d864a1ee1ce3ead9c

    BSC

    ETH

    0x2170Ed0880ac9A755fd29B2688956BD959F933F8

    BSC

    WUNIT0

    0xe80698d9c55d9212c4dae8bed00e1357d804c62a

    BSC

    OGC

    0x21b1b07af26613479e526c058749239e460f8a2f

    Base

    crvUSD

    0x417Ac0e078398C154EdFadD9Ef675d30Be60Af93

    Base

    scrvUSD

    0x646A737B9B6024e49f5908762B3fF73e65B5160c

    Base

    USDbC

    0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA

    Base

    axlUSDC

    0xEB466342C4d449BC9f53A865D5Cb90586f405215

    Base

    USDC

    0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913

    Base

    USDM

    0x59D9356E565Ab3A36dD77763Fc0d87fEaf85508C

    Base

    CRV

    0x8Ee73c484A26e0A5df2Ee2a4960B789967dd0415

    Base

    cbBTC

    0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf

    Base

    ETH

    native coin

    Base

    WETH

    0x4200000000000000000000000000000000000006

    Base

    superOETHb

    0xDBFeFD2e8460a6Ee4955A68582F85708BAEA60A3

    Gnosis

    USDC

    0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83

    Gnosis

    USDT

    0x4ECaBa5870353805a9F068101A40E0f32ed605C6

    Gnosis

    WXDAI

    0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d

    Gnosis

    EURe

    0xcB444e90D8198415266c6a2724b7900fb12FC56E

    Gnosis

    EURC.e

    0x54E4cB2a4Fa0ee46E3d9A98D13Bea119666E09f6

    Gnosis

    CRV

    0x712b3d230f3c1c19db860d80619288b1f0bdd0bd

    Gnosis

    WETH

    0x6a023ccd1ff6f2045c3309768ead9e68f978f6e1

    Gnosis

    WBTC

    0x8e5bbbb09ed1ebde8674cda39a0c169401db4252

    Blast

    USDB

    0x4300000000000000000000000000000000000003

    Blast

    ETH

    native coin

    Blast

    WETH

    0x4300000000000000000000000000000000000004

    Blast

    OGC

    0xf08e269cd00c4713fe880d4c550f779d329b6f48

    Mantle

    USDC

    0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9

    Mantle

    WETH

    0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111

    Mantle

    OGC

    0xf08e269cd00c4713fe880d4c550f779d329b6f48

    Linea

    USDC.e

    0x176211869cA2b568f2A7D4EE941E073a821EE1ff

    Linea

    WBTC

    0x3aab2285ddcddad8edf438c1bab47e1a9d05a9b4

    Linea

    ETH

    native coin

    Linea

    WETH

    0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f

    Linea

    OGC

    0xf08e269cd00c4713fe880d4c550f779d329b6f48

    Taiko

    crvUSD

    0xc8F4518ed4bAB9a972808a493107926cE8237068

    Taiko

    USDC

    0x07d83526730c7438048D55A4fc0b850e2aaB6f0b

    Taiko

    USDT

    0x2def195713cf4a606b49d07e520e22c17899a736

    Taiko

    ETH

    native coin

    Taiko

    WETH

    0xa51894664a773981c6c112c43ce576f315d5b1b6

    Kava

    USDt

    0x919C1c267BC06a7039e03fcc2eF738525769109c

    Celo

    USDC

    0xceba9300f2b948710d2653dd7b07f33a8b32118c

    Celo

    USD₮

    0x48065fbbe25f71c9282ddf5e1cd6d6a887483d5e

    Celo

    cUSD

    0x765de816845861e75a25fca122bb6898b8b1282a

    Fraxtal

    USDT

    0x4d15ea9c2573addaed814e48c148b5262694646a

    Fraxtal

    CRV

    0x331b9182088e2a7d6d3fe4742aba1fb231aecc56

    Fraxtal

    FRAX

    0xfc00000000000000000000000000000000000001

    Fraxtal

    wfrxETH

    0xfc00000000000000000000000000000000000006

    Metis

    m.USDT

    0xbB06DCA3AE6887fAbF931640f67cab3e3a16F4dC

    Metis

    WETH

    0x420000000000000000000000000000000000000A

    Metis

    OGC

    0xf08e269cd00c4713fe880d4c550f779d329b6f48

    Mode

    USDC

    0xd988097fb8612cc24eeC14542bC03424c656005f

    Mode

    WETH

    0x4200000000000000000000000000000000000006

    Manta

    USDT

    0xf417F5A458eC102B90352F697D6e2Ac3A3d2851f

    Manta

    WETH

    0x0Dc808adcE2099A9F62AA87D9670745AbA741746

    Mantle

    USDC

    0x09bc4e0d864854c6afb6eb9a9cdf58ac190d0df9

    Unit Zero

    UNIT0

    GjwAHMjqWzYR4LgoNy91CxUKAGJN79h2hseZoae4nU8t

    Unit Zero

    WUNIT0

    0xCF43F7703d9B4E8835f977eF364B4014fA7e856E

    Unit Zero

    USDC

    0xEb19000D90f17FFbd3AD9CDB8915D928F4980fD1

    Unit Zero

    USDT

    0xb303d80db8415FD1d3C9FED68A52EEAc9a052671

    Unit Zero

    WETH

    0x1B100DE3F13E3f8Bb2f66FE58c1949c32E71248B

    Unit Zero

    WBTC

    0x9CE808657ba90C65a2700b1cA5D943eC72834B52

    Fantom

    USDC

    0x28a92dde19D9989F39A49905d7C9C2FAc7799bDf

    Fantom

    USDC.e

    0x2F733095B80A04b38b0D10cC884524a3d09b836a

    Fantom

    CRV

    0xE6c259bc0FCE25b71fE95A00361D3878E16232C3

    Fantom

    WFTM

    0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83

    Sonic

    USDC.e

    0x29219dd400f2bf60e5a23d13be72b486d4038894

    Sonic

    USDT

    0x6047828dc181963ba44974801FF68e538dA5eaF9

    Sonic

    scUSD

    0xd3dce716f3ef535c5ff8d041c1a41c3bd89b97ae

    Sonic

    frxUSD

    0x80eede496655fb9047dd39d9f418d5483ed600df

    Sonic

    WETH

    0x50c42dEAcD8Fc9773493ED674b675bE577f2634b

    Sonic

    scETH

    0x3bce5cb273f0f148010bbea2470e7b5df84c7812

    Sonic

    frxETH

    0x43edd7f3831b08fe70b7555ddd373c8bf65a9050

    Sonic

    scBTC

    0xBb30e76d9Bb2CC9631F7fC5Eb8e87B5Aff32bFbd

    Sonic

    stS

    0xe5da20f15420ad15de0fa650600afc998bbe3955

    Sonic

    cmGEMS1

    0x3301e4326cf2939cd6b8f23ddf7bc2a1713fd06a

    Ethereum

    crv3crypto

    0xd51a44d3fae010294c616388b506acda1bfaae46

    Ethereum

    crvUSDUSDC-f

    0x4dece678ceceb27446b35c672dc7d61f30bad69e

    Curve LPs

    EYWA
    crvUSDUSDT-f
    3Crv
    tBTC/WBTC
    3c-crvUSD
    crvUSDC
    crvUSDT
    2CRV
    2BTC-ng
    3UNIT
    EYWA/USDT
    crvUSDBTCETH
    WMATIC/TRICRYPTO
    crvusdusdc
    crvusdusdt
    am3CRV
    CRVTRI-f
    crvUSDBTCETH
    2BTC
    av3CRV
    crvUSDC
    Tricrypto-crvUSD
    crvUSDT
    3CRV
    crvusdUSDC
    crvusdUSDT
    b3pool
    tricrypto
    4poolUSD-f
    x3CRV
    3pool
    Tri-Pool
    FRAX/USDT
    xCRVUSDT
    xCRVUSDC
    x3CRYPTO
    xSTABLE
    xSTABLE2
    xSTABLE3
    xWETH
    xWETH2
    xBTC
    wFTM/USDC
    xCRV
    xfrxUSD
    xfrxETH
    xsEthereum
    xsBSC
    xsAvalanche
    xsPolygon
    xsArbitrum
    xsOptimism
    xsBase
    xsBlast
    xsGnosis
    xsTaiko
    xsMantle
    xsLinea
    xsCelo
    xsMetis
    xsMode
    xsManta
    xsKava
    xeEthereum
    xeArbitrum
    xeOptimism
    xeBase
    xeBlast
    xeMantle
    xeBSC
    xePolygon
    xeAvalanche
    xeGnosis
    xeMetis
    xeMode
    xeLinea
    xeTaiko
    xeManta
    xbEthereum
    xbArbitrum
    xbOptimism
    xbAvalanche
    xbPolygon
    xbBSC
    xbBase
    xbLinea
    xbGnosis
    xcmGEMS1
    USDC/USDT

    Hubchain Pools and Assets

    CrossCurve pools and assets are integrated within the Sonic (previously Fantom) and Arbitrum ecosystems.

    CrossCurve facilitates the swapping of s-tokens within Curve pools on the Sonic (in archive pools also Fantom), Arbitrum and Taiko Hubchains. All liquidity in CrossCurve on Hubchain is composed of s-tokens. These s-tokens are collateralized synthetic assets issued by the CrossCurve Consensus Bridge. Each s-token is fully backed by the original asset to which it is pegged, with these assets securely locked in the CrossCurve Token Bridge on the source blockchain. Audited by SmartState.

    Specialized tokenized assets that facilitate cross-chain trading and yield generation. These s-tokens, typically part of CrossCurve's core stable pools, enable the exchange of similar tokens, thereby creating a unified cross-chain liquidity market. By aggregating liquidity across various blockchains, s-tokens play a pivotal role in streamlining cross-chain operations and enhancing the efficiency of decentralized trading within the Curve-based protocol.

    CrossCurve supports the use of both standard assets and LP tokens as collateral for s-tokens. Below, you will find a list of cross-chain pools, the s-tokens they contain, and the assets backing them.

    Pool page:

    Pool/token:

    CrossCurve frxUSD pool assets:

    Universal token
    Source chain

    Pool page:

    Pool/token:

    CrossCurve frxETH pool assets:

    Universal token
    Source chain

    Pool page: Pool/token: CrossCurve Stable ETH pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable BSC pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable AVA pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable POL pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable ARB pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable OP pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable BASE pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable BL pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable GNO pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Curve LP (collateral)
    Pool page
    Source chain

    CrossCurve Stable MTL

    Pool page: Pool/token: CrossCurve Stable MTL pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable LIN pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable CELO pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable MET pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable MODE pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable MTA pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve Stable KAVA pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH ETH pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH ARB pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH OP pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    CrossCurve WETH BASE

    Pool page: Pool/token: CrossCurve WETH BASE pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH BL pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH MTL pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH BSC pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH POL pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH AVA pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH GNO pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH MET pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH MODE pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH LIN pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve WETH MTA pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve BTC ETH pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve BTC ARB pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve BTC OP pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve BTC AVA pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve BTC POL pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve BTC BSC pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve BTC BASE pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve BTC LIN pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page: Pool/token: CrossCurve BTC GNO pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page:

    Pool/token:

    CrossCurve xCRV pool assets:

    S-token
    Curve LP (collateral)
    Pool page
    Token
    Source chain

    Pool page:

    Pool/token:

    CrossCurve xCRV2 pool assets:

    S-token
    Curve LP (collateral)
    Pool page
    Token
    Source chain

    Pool page:

    Pool/token:

    CrossCurve CRV/USD pool assets:

    S-token
    Curve LP (collateral)
    Pool page
    Token
    Source chain

    Pool page:

    Pool/token:

    CrossCurve cmGEMS1 pool assets:

    Token
    Source chain

    CrossCurve Stable TAI

    Pool page: Pool/token: CrossCurve Stable TAI pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Curve LP (collateral)
    Pool page
    Source chain

    Pool page: Pool/token: CrossCurve WETH TAI pool assets:

    Universal token
    Synthetic derivative
    S-token collateral
    Source chain

    Pool page:

    Pool/token:

    CrossCurve EYWAUSDT pool assets:

    Token
    Source chain

    Pool page:

    Pool/token:

    UNIT0/WUNIT0 pool assets:

    S-token
    Token
    Source chain

    Pool page:

    Pool/token:

    3UNIT0 pool assets:

    S-token
    Token
    Source chain

    CrossCurve Stable pool

    Pool page:

    Pool/token:

    CrossCurve Stable pool assets:

    CrossCurve WETH pool

    Pool page:

    Pool/token:

    CrossCurve Stable pool assets:

    Pool page:

    Pool/token:

    Token
    Source chain

    Pool page:

    Pool/token:

    CrossCurve xSTABLE pool assets:

    S-token
    Curve LP (collateral)
    Pool contract
    Pool page
    Source chain

    Pool page:

    Pool/token:

    CrossCurve xSTABLE2 pool assets:

    S-token
    Curve LP (collateral)
    Pool page
    Token
    Source chain

    Pool page:

    Pool/token:

    CrossCurve xSTABLE3 pool assets:

    S-token
    Curve LP (collateral)
    Pool page
    Token
    Source chain

    Pool page:

    Pool/token:

    CrossCurve xWETH pool assets:

    S-token
    Token
    Source chain

    Pool page:

    Pool/token:

    CrossCurve xWETH2 pool assets:

    S-token
    Token
    Source chain

    Pool page:

    Pool/token:

    CrossCurve xBTC pool assets:

    S-Token
    Curve LP (collateral)
    Pool page
    Token
    Source chain

    Pool page:

    Pool/token :

    CrossCurve 3crypto pool assets:

    S-token
    Curve LP (collateral)
    Pool contract
    Pool page
    Source chain

    Pool page:

    Pool/token :

    CrossCurve crvUSDC pool assets:

    S-token
    Curve LP (collateral)
    Pool contact
    Pool page
    Source chain

    Pool page:

    Pool/token :

    CrossCurve crvUSDT pool assets:

    S-token
    Curve LP (collateral)
    Pool contract
    Pool page
    Source chain

    Sonic

    Ethereum

    Sonic

    BSC

    Sonic

    Avalanche

    Sonic

    Polygon

    Sonic

    Arbitrum

    Sonic

    Optimism

    Sonic

    Base

    Sonic

    Blast

    Sonic

    Sonic

    Gnosis

    Gnosis

    Gnosis

    Gnosis

    Sonic

    Mantle

    Sonic

    Linea

    Sonic

    Celo

    Sonic

    Metis

    Sonic

    Mode

    Sonic

    Manta

    Sonic

    Kava

    Sonic

    Ethereum

    Sonic

    Arbitrum

    Sonic

    Optimism

    Sonic

    Base

    Sonic

    Blast

    Sonic

    Mantle

    Sonic

    BSC

    Sonic

    Polygon

    Sonic

    Avalanche

    Sonic

    Gnosis

    Sonic

    Metis

    Sonic

    Mode

    Sonic

    Linea

    Sonic

    Manta

    Sonic

    Ethereum

    Sonic

    Arbitrum

    Sonic

    Optimism

    Sonic

    Avalanche

    Sonic

    Polygon

    Sonic

    BSC

    Sonic

    Base

    Sonic

    Linea

    Sonic

    Gnosis

    Arbitrum

    Base

    Optimism

    Polygon

    Gnosis

    Fraxtal

    Fantom

    Taiko

    Sonic

    Sonic

    Sonic

    Sonic

    Taiko

    Taiko

    Taiko

    Sonic

    Taiko

    Arbitrum

    Arbitrum

    Optimism

    Avalanche

    Polygon

    BSC

    Base

    Gnosis

    Mantle

    Blast

    Linea

    Taiko

    Celo

    Fraxtal

    Kava

    Fantom

    Metis

    Mode

    Fantom

    Fantom

    Manta

    Sonic

    Optimism

    Base

    Mantle

    Blast

    Linea

    Taiko

    BSC

    Fraxtal

    Gnosis

    Metis

    Mode

    Arbitrum

    Optimism

    Avalanche

    Polygon

    BSC

    Base

    Linea

    Arbitrum

    Avalanche

    Polygon

    Arbitrum

    Optimism

    Polygon

    BNB chain

    (3pool)

    Avalanche

    Arbitrum

    Optimism

    Polygon

    BNB chain

    Avalanche

    scUSD

    Sonic

    frxUSD

    Sonic

    scETH

    Sonic

    frxETH

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxUSD

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    xfrxETH

    Sonic

    scBTC

    Sonic

    scBTC

    Sonic

    scBTC

    Sonic

    scBTC

    Sonic

    scBTC

    Sonic

    scBTC

    Sonic

    scBTC

    Sonic

    scBTC

    Sonic

    scBTC

    Sonic

    sCRV_e

    CRV

    xCRV

    CrossCurve CRV

    xCRV2

    CrossCurve CRV 2

    stS

    Sonic

    cmGEMS1

    Sonic

    xfrxUSD

    xfrxETH

    Sonic

    EYWA

    Arbitrum

    USD₮0

    Arbitrum

    synth - Ethereum UNIT0

    UNIT0

    Arbitrum

    synth - Units WUNIT0

    WUNIT0

    Arbitrum

    synth - Units WUNIT0

    WUNIT0

    Arbitrum

    WETH

    WETH

    Arbitrum

    sxfrxUSD_s

    Taiko

    USDC

    Taiko

    Token

    Source chain

    sxfrxETH_s

    Taiko

    WETH

    Taiko

    USDC

    Fantom

    WFTM

    Fantom

    s3CRV_e

    3Crv

    3Pool

    3Pool

    xSTABLE

    xSTABLE

    xSTABLE

    xSTABLE

    sWETH_e

    WETH

    Ethereum

    sWETH_ar

    WETH

    Arbitrum

    sWETH.e_av

    WETH.e

    Avalanche

    sWETH_p

    WETH

    Polygon

    s2BTC_e

    tBTC/WBTC

    tBTC/WBTC

    s3crypto_e

    crv3crypto

    tricrypto2

    tricrypto2

    scrvUSDC_e

    crvUSDUSDC-f

    crvUSD/USDC

    crvUSD/USDC

    scrvUSDT_e

    crvUSDUSDT-f

    crvUSD/USDT

    crvUSD/USDT

    Each paired pool on the Sonic (or Taiko) Hubchain consists of two tokens:

    • A universal token – an asset from Sonic, uniform across all pools of the same type (e.g., xfrxUSD for USD assets, xfrxETH for ETH, and scBTC for BTC). More details .

    • A synthetic derivative (s-token), backed by the original asset locked in the Consensus Bridge. These can be either single assets or LP tokens from Curve.

    Synthetic tokens are categorized into three types:

    • s_Stable_chain, where Stable represents a USD asset variant, and chain is the network where the asset is used.

    • s_WETH_network, where WETH represents ETH backing, and chain is the network where the asset is used.

    Each type of synthetic token corresponds to a pool where it can be paired in an LP token:

    • xs_chain, where xs is a stable pool, and chain is the network where the asset is used.

    • xe_chain, where xe is a volatile pool, and chain is the network where the asset is used.

    To understand the naming convention of s-tokens on CrossCurve, particularly when incorporating a list of supported networks within the name, such as "sUSDT_eth," let's break it down:

    • The prefix "s" typically stands for "synthetic", indicating the type of token.

    • The main body of the name, such as "USDT" specifies the underlying asset. Here, "USDT" indicates that the token is related to CrossCurve Stable pools.

    • The suffix after an underscore, such as "eth," represents the network on which the token operates. For instance, "eth" might denote the Ethereum network.

    In this naming structure, "sUSDT_eth" would represent a synthetic version of the CrossCurve s-token operating on the Ethereum network, to work with the liquidity in the CrossCurve Stable ETH pool.

    Each different suffix corresponds to other supported networks, providing a quick reference to the cross-chain capabilities of the s-token within the CrossCurve platform:

    eth - Ethereum network

    arb - Arbitrum network

    op - Optimism network

    av - Avalanche network

    p - Polygon network

    b - Binance Smart Chain network

    ba - Base network

    g - Gnosis network

    m - Mantle network

    me - Metis network

    mo - Mode network

    ma - Manta network

    bl - Blast network

    l - Linea network

    c - Celo network

    ka - Kava nework

    For archived pools on Fantom, each different body of the name, such as "crvUSDT," specifies the supported pool:

    crvUSDT - xCRVUSDT pool

    crvUSDC - xCRVUSDC pool

    3CRV - xCRVUSDT, xCRVUSDC, xSTABLE pools

    3crypto - x3CRYPTO pool

    2CRV, 3Pool, 4Pool - xSTABLE pool

    USDC, USDT, USDB, USDCe, 3pool, FrUsdt, USDt - xSTABLE2, xSTABLE3 pools

    WETH - xWETH, xWETH2 pools

    ETH, wfrxETH - xWETH2 pool

    2BTC, BTC.b, WBTC, BTCB, cbBTC - xBTC pool

    CRV, CRVTRI - xCRV pool

    LP tokens in the CrossCurve ecosystem offer liquidity providers a means to engage with various DeFi platforms across multiple blockchains simultaneously. By providing liquidity, participants receive LP tokens, which represent a claim on their share of the pool's assets and its yield. Holding LP tokens allows providers not only to decide when to withdraw their assets but also to benefit from enhanced returns through cumulative rewards from both Curve and the CrossCurve DAO. Essentially, LP tokens signify ownership of a portion of the liquidity pool, enabling providers to earn returns on their stakes and facilitating cross-chain transactions within the Curve finance ecosystem.

    Sonic pools

    Main pools

    CrossCurve frxUSD

    CrossCurve frxETH

    xsStable pools

    Synthetic tokens are categorized into three types:

    • s_Stable_chain, where Stable represents a USD asset variant, and chain is the network where the asset is used.

    Each type of synthetic token corresponds to a pool where it can be paired in an LP token:

    • xs_chain, where xs is a stable pool, and chain is the network where the asset is used.

    CrossCurve Stable ETH

    CrossCurve Stable BSC

    CrossCurve Stable AVA

    CrossCurve Stable POL

    CrossCurve Stable ARB

    CrossCurve Stable OP

    CrossCurve Stable BASE

    CrossCurve Stable BL

    CrossCurve Stable GNO

    CrossCurve Stable LIN

    CrossCurve Stable CELO

    CrossCurve Stable MET

    CrossCurve Stable MODE

    CrossCurve Stable MTA

    CrossCurve Stable KAVA

    xeWETH pools

    Synthetic tokens are categorized into three types:

    • s_WETH_network, where WETH represents ETH backing, and chain is the network where the asset is used.

    Each type of synthetic token corresponds to a pool where it can be paired in an LP token:

    • xe_chain, where xe is a volatile pool, and chain is the network where the asset is used.

    CrossCurve WETH ETH

    CrossCurve WETH ARB

    CrossCurve WETH OP

    CrossCurve WETH BL

    CrossCurve WETH MTL

    CrossCurve ETH BSC

    CrossCurve WETH POL

    CrossCurve WETH AVA

    CrossCurve WETH GNO

    CrossCurve WETH MET

    CrossCurve WETH MODE

    CrossCurve WETH LIN

    CrossCurve WETH MTA

    xbBTC

    Synthetic tokens are categorized into three types:

    • s_WBTC_network, where WBTC represents BTC backing, and chain is the network where the asset is used.

    Each type of synthetic token corresponds to a pool where it can be paired in an LP token:

    • xb_chain, where xb is a volatile pool, and chain is the network where the asset is used.

    CrossCurve BTC ETH

    CrossCurve BTC ARB

    CrossCurve BTC OP

    CrossCurve BTC AVA

    CrossCurve BTC POL

    CrossCurve BTC BSC

    CrossCurve BTC BASE

    CrossCurve BTC LIN

    CrossCurve BTC GNO

    xToken pools

    CrossCurve xCRV pool

    CrossCurve CRV 2 pool

    CrossCurve CRV/USD pool

    CrossCurve cmGEMS1

    Outdated pools

    CrossCurve WETH TAI

    Arbitrum pools

    CrossCurve EYWAUSDT pool

    UNIT0/WUNIT0 pool

    3UNIT0 pool

    Taiko pools

    Fantom pools

    xToken pools

    CrossCurve wFTM/USDC pool

    Outdated pools

    xSTABLE pools

    CrossCurve xSTABLE pool (old)

    CrossCurve xSTABLE2 pool (old)

    CrossCurve xSTABLE3 pool (old)

    xWETH pools

    CrossCurve xWETH pool (old)

    CrossCurve xWETH2 pool (old)

    xBTC pools

    CrossCurve xBTC pool (old)

    xToken pools

    CrossCurve 3crypto pool (old)

    CrossCurve crvUSDC pool (old)

    CrossCurve crvUSDT pool (old)

    https://curve.finance/dex/sonic/pools/factory-stable-ng-25/deposit/
    xfrxUSD
    https://curve.finance/dex/sonic/pools/factory-stable-ng-26/deposit/
    xfrxETH
    https://curve.finance/dex/#/sonic/pools/factory-stable-ng-2/deposit
    xsEthereum
    https://curve.finance/dex/sonic/pools/factory-stable-ng-70/deposit/
    xsBSC
    https://curve.finance/dex/sonic/pools/factory-stable-ng-71/deposit/
    xsAva
    https://curve.finance/dex/sonic/pools/factory-stable-ng-72/deposit/
    xsPolygon
    https://curve.finance/dex/sonic/pools/factory-stable-ng-73/deposit/
    xsArbitrum
    https://curve.finance/dex/sonic/pools/factory-stable-ng-74/deposit/
    xsOptimism
    https://curve.finance/dex/sonic/pools/factory-stable-ng-75/deposit/
    xsBase
    https://curve.finance/dex/sonic/pools/factory-stable-ng-76/deposit/
    xsBlast
    https://curve.finance/dex/sonic/pools/factory-stable-ng-77/deposit/
    xsGnosis
    https://curve.finance/dex/sonic/pools/factory-stable-ng-79/deposit/
    xsMantle
    https://curve.finance/dex/sonic/pools/factory-stable-ng-80/deposit/
    xsLinea
    https://curve.finance/dex/sonic/pools/factory-stable-ng-81/deposit/
    xsCelo
    https://curve.finance/dex/sonic/pools/factory-stable-ng-82/deposit/
    xsMetis
    https://curve.finance/dex/sonic/pools/factory-stable-ng-83/deposit/
    xsMode
    https://curve.finance/dex/sonic/pools/factory-stable-ng-84/deposit/
    xsManta
    https://curve.finance/dex/sonic/pools/factory-stable-ng-85/deposit/
    xsKava
    https://curve.finance/dex/sonic/pools/factory-stable-ng-86/deposit/
    xeEthereum
    https://curve.finance/dex/sonic/pools/factory-stable-ng-87/deposit/
    xeArbitrum
    https://curve.finance/dex/sonic/pools/factory-stable-ng-88/deposit/
    xeOptimism
    https://curve.finance/dex/sonic/pools/factory-stable-ng-89/deposit/
    xeBase
    https://curve.finance/dex/sonic/pools/factory-stable-ng-90/deposit/
    xeBlast
    https://curve.finance/dex/sonic/pools/factory-stable-ng-91/deposit/
    xeMantle
    https://curve.finance/dex/sonic/pools/factory-stable-ng-92/deposit/
    xeBSC
    https://curve.finance/dex/sonic/pools/factory-stable-ng-93/deposit/
    xePolygon
    https://curve.finance/dex/sonic/pools/factory-stable-ng-94/deposit/
    xeAva
    https://curve.finance/dex/sonic/pools/factory-stable-ng-95/deposit/
    xeGnosis
    https://curve.finance/dex/sonic/pools/factory-stable-ng-96/deposit/
    xeMetis
    https://curve.finance/dex/sonic/pools/factory-stable-ng-97/deposit/
    xeMode
    https://curve.finance/dex/sonic/pools/factory-stable-ng-98/deposit/
    xeLinea
    https://curve.finance/dex/sonic/pools/factory-stable-ng-100/deposit/
    xeManta
    https://curve.finance/dex/sonic/pools/factory-stable-ng-60/deposit/
    xbEthereum
    https://curve.finance/dex/sonic/pools/factory-stable-ng-61/deposit/
    xbArbitrum
    https://curve.finance/dex/sonic/pools/factory-stable-ng-62/deposit/
    xbOptimism
    https://curve.finance/dex/sonic/pools/factory-stable-ng-63/deposit/
    xbAva
    https://curve.finance/dex/sonic/pools/factory-stable-ng-64/deposit/
    xbPolygon
    https://curve.finance/#/sonic/pools/factory-stable-ng-65/deposit
    xbBSC
    https://curve.finance/dex/sonic/pools/factory-stable-ng-66/deposit/
    xbBase
    https://curve.finance/dex/sonic/pools/factory-stable-ng-67/deposit/
    xbLinea
    https://curve.finance/dex/sonic/pools/factory-stable-ng-68/deposit/
    xbGnosis
    https://curve.finance/dex/#/sonic/pools/factory-stable-ng-2/deposit
    xCRV
    https://www.curve.finance/dex/sonic/pools/factory-stable-ng-106/deposit/
    xCRV2
    https://www.curve.finance/dex/sonic/pools/factory-twocrypto-29/deposit/
    CRV/USD
    https://curve.finance/dex/sonic/pools/factory-twocrypto-22/deposit/
    xcmGEMS1
    https://curve.finance/dex/sonic/pools/factory-stable-ng-78/deposit/
    xsTaiko
    https://curve.finance/dex/sonic/pools/factory-stable-ng-99/deposit/
    xeTaiko
    https://curve.finance/dex/arbitrum/pools/factory-twocrypto-57/deposit/
    EYWAUSDT
    https://curve.finance/#/arbitrum/pools/factory-stable-ng-109/deposit
    UNIT0/WUNIT0
    https://curve.finance/#/arbitrum/pools/factory-tricrypto-38/deposit
    3UNIT0
    https://www.curve.finance/dex/taiko/pools/factory-stable-ng-5/deposit/
    xsoTaiko
    https://www.curve.finance/dex/taiko/pools/factory-stable-ng-6/deposit/
    xeoTaiko
    https://curve.finance/dex/fantom/pools/factory-twocrypto-53/deposit/
    wFTM/USDC
    https://curve.finance/#/fantom/pools/factory-stable-ng-24/deposit
    xSTABLE
    https://curve.finance/#/fantom/pools/factory-stable-ng-43/deposit
    xSTABLE2
    https://curve.finance/#/fantom/pools/factory-stable-ng-54/deposit
    xSTABLE3
    https://curve.finance/#/fantom/pools/factory-stable-ng-37/deposit
    xWETH
    https://curve.finance/#/fantom/pools/factory-stable-ng-49/deposit
    xWETH2
    https://curve.finance/#/fantom/pools/factory-stable-ng-39/deposit
    xBTC
    https://curve.finance/#/fantom/pools/factory-stable-ng-17/deposit
    x3CRYPTO
    https://curve.finance/#/fantom/pools/factory-stable-ng-16/deposit
    xCRVUSDC
    https://curve.finance/#/fantom/pools/factory-stable-ng-20/deposit
    xCRVUSDT

    Ethereum

    Sonic

    Sonic

    Ethereum

    Fantom

    Fantom

    Ethereum

    Ethereum

    Ethereum

    Ethereum

    s_WBTC_network, where WBTC represents BTC backing, and chain is the network where the asset is used.

    xb_chain, where xb is a volatile pool, and chain is the network where the asset is used.

    here
    sUSDT_eth
    USDT
    sUSDT_b
    USDT
    sUSDt_av
    USDt
    sUSDT_p
    USDT
    sUSDC_arb
    USDC
    sUSDT_op
    USDT
    sUSDC_ba
    USDC
    sUSDB_bl
    USDB
    sx3CRV_g
    WXDAI
    USDC
    USDT
    3pool
    3Pool
    sUSDC_m
    USDC
    sUSDC_l
    USDC
    sUSDT_ce
    USD₮
    sm.USDT_me
    m.USDT
    sUSDC_mo
    USDC
    sUSDT_ma
    USDT
    sUSDt_ka
    USDt
    sWETH_e
    WETH
    sWETH_ar
    WETH
    sWETH_op
    WETH
    sWETH_ba
    WETH
    sWETH_bl
    WETH
    sWETH_m
    WETH
    sETH_b
    ETH
    sWETH_p
    WETH
    sWETH.e_av
    WETH.e
    sWETH_g
    WETH
    sWETH_me
    WETH
    sWETH_mo
    WETH
    sWETH_l
    WETH
    sWETH_ma
    WETH
    sWBTC_e
    WBTC
    sWBTC_ar
    WBTC
    sWBTC_op
    WBTC
    sBTC.b_av
    BTC.b
    sWBTC_p
    WBTC
    sBTCB_b
    BTCB
    scbBTC_ba
    cbBTC
    sWBTC_l
    WBTC
    sWBTC_g
    WBTC
    sCRV_ar
    CRV
    sCRV_ba
    CRV
    sCRV_o
    CRV
    sCRV_p
    CRVTRI-f
    CRV/TRICRYPTO
    CRV
    sCRV_g
    CRV
    sCRV_fr
    CRV
    sCRV_ft
    CRV
    sCRV_t
    CRV
    CRV
    xfrxUSD
    CrossCurve frxUSD
    s2Pool_t
    USDC
    USDT
    USDC/USDT
    USDC/USDT
    sWETH_t
    WETH
    s2CRV_ar
    2CRV
    s2CRV_ar
    2CRV
    2Pool
    2Pool
    s3CRV_o
    3CRV
    3Pool
    3Pool
    sav3CRV_av
    av3CRV
    aave
    aave
    sam3CRV_p
    am3CRV
    aave
    aave
    sb3pool_b
    b3pool
    b3pool
    b3pool
    s4pool_ba
    4poolUSD-f
    4pool
    4Pool
    sx3CRV_g
    x3CRV
    3Pool
    3Pool
    sUSDC_m
    USDC
    sUSDB_bl
    USDB
    sUSDCe_l
    USDC.e
    sUSDC_t
    USDC
    s3Pool_c
    Tri-Pool
    Tri-Pool
    sFrUsdt_t
    FRAX/USDT
    FRAX/USDT
    sUSDt_t
    USDt
    xSTABLE2
    xSTABLE2
    sm.USDT_me
    m.USDT
    sUSDC_mo
    USDC
    USDC.e
    USDC
    sUSDT_ma
    USDT
    sUSDC.e_s
    USDC.e
    sWETH_o
    WETH
    sWETH_ba
    WETH
    sWETH_m
    WETH
    sWETH_bl
    WETH
    sWETH_l
    WETH
    sWETH_t
    WETH
    sETH_b
    ETH
    swfrxETH_f
    wfrxETH
    sWETH_gn
    WETH
    sWETH_me
    WETH
    sWETH_mo
    WETH
    s2BTC_ar
    2BTC-ng
    2BTC-ng
    s2BTC_o
    2BTC
    2BTC
    sBTC.b_av
    BTC.b
    sWBTC_p
    WBTC
    sBTCB_b
    BTCB
    scbBTC_ba
    cbBTC
    sWBTC_l
    WBTC
    s3crypto_ar
    3c-crvUSD
    3c-crvUSD
    Tricrypto-crvUSD
    s3crypto_av
    crvUSDBTCETH
    atricrypto
    atricrypto
    s3crypto_p
    crvUSDBTCETH
    atricrypto3
    atricrypto3
    scrvUSDC_ar
    crvUSDC
    crvUSD/USDC
    crvUSD/USDC
    scrvUSDC_o
    crvUSDC
    crvUSD/USDC
    crvUSD/USDC
    scrvUSDC_p
    crvusdusdc
    crvUSD/USDC
    crvUSD/USDC
    scrvUSDC_b
    crvusdUSDC
    crvUSD/USDC
    crvUSD/USDC
    sav3CRV_av
    av3CRV
    aave
    aave
    scrvUSDT_ar
    crvUSDT
    crvUSD/USDT
    crvUSD/USDT
    scrvUSDT_o
    crvUSDT
    crvUSD/USDT
    crvUSD/USDT
    scrvUSDT_p
    crvusdusdt
    crvUSD/USDT
    crvUSD/USDT
    scrvUSDT_b
    crvusdUSDT
    crvUSD/USDT
    crvUSD/USDT
    sav3CRV_av
    av3CRV
    aave
    aave