SNS Liquidity Pools - Design

:droplet::pool_8_ball: SNS Liquidity Pools

TL;DR

We propose to implement a Liquidity Pool Extension for SNSs that allows allocating some SNS treasury tokens in a DEX to support exchanging SNS tokens (for existing and new SNSs).

We’re looking for feedback on the high-level design.

Background

Participants of an SNS launch should be able to use decentralized exchanges (DEXs) to exchange liquid SNS tokens obtained after a successful swap. Currently, this requires a lot of manual work for each DEX: registering the new tokens, the desired exchange pair (e.g., SNS:ICP), and adding tokens to the corresponding liquidity pool (a pair of DEX-controlled accounts used to support instant exchanges).

Even then, it is not practically possible to exchange tokens freely until a substantial amount of liquidity is added. This requires either a large number of liquidity providers or multiple SNS treasury transfers to the liquidity pool; either way, the process is slow and requires some sort of off-chain coordination. As a result, many SNSs currently do not have a realistic and fair way to exchange their tokens, even months after the launch. This makes swap participation less attractive.

Currently, SNS DAOs mitigate the problem by using a combination of treasury transfer proposals and custom functions that are specific to each individual DEX. However, keeping track of multiple proposals to achieve a single goal (i.e., allocate part of the treasury funds in a liquidity pool) is complicated for the voters, and is thus error prone. Currently, SNSs cannot easily withdraw their tokens from liquidity pools.

An additional complication stems from the lack of a common DEX standard; each DEX on ICP has its own custom interface. On the one hand, this makes it challenging to support arbitrary DEXs in the SNS framework. On the other hand, there are different DEXs on ICP, so tailoring the SNS to work with just one DEX is insufficient.

Overview

The SNS Liquidity Pools feature will enable SNS DAOs to allocate some part of the treasury tokens into liquidity pools on specific DEXs. The liquidity will support a more stable and efficient market for the SNS ecosystem.

Key Components

At the core of the design is a new class of canisters that can directly integrate with SNSs to manage parts of the treasury, called the Liquidity Pool Extension (one for each supported DEX). This canister is deployed and controlled solely by the SNS, with its code being open source and thoroughly audited (we will list the exact technical requirements in the next iteration if we go forward with this design).

While all Liquidity Pool Extension canisters encapsulate DEX-specific code, they integrate into the SNS framework via the same simple API. This has the advantage that all proposals for allocating treasury funds into liquidity pools are the same, no matter the DEX they interact with, making it a lot easier for SNS users to understand and vote on them.

This design avoids tailoring the SNS framework to a fixed set of DEXs. Any DEXs, including existing and future ones, can provide its own Liquidity Pool Extension canister. DFINITY will build the first proof of concept, but subsequent Liquidity Pool Extensions can be built either by the DEX developers or any other party, so long as they meet the technical requirements and are approved by the NNS.

The Liquidity Pool Extension provides the following key functionality:

  • Deposits: An SNS can deposit some SNS and ICP tokens from its treasury into a DEX. For existing SNSs, this will require a critical proposal, while for a new SNS, its initial DEX deposit could be specified in the CreateSNS proposal. Each supported DEX will require its own Liquidity Pool Extension canister.
  • Observability: The Liquidity Pool Extension provides an audit trail API for clients to check their SNS’s balances and to perform audits based on all ledger transactions involved in managing SNS assets.
  • Efficiency: The Liquidity Pool Extension will automatically send all unused tokens back to the SNS treasury.
  • Withdrawals: An SNS can fully withdraw all remaining tokens from its DEX allocation via a critical proposal.

Benefits

The SNS Liquidity Pools feature will bring several benefits:

  • Increased Liquidity: Ensuring smoother token exchanging and price stability.
  • Simpler user flow: One proposal per DEX allocation; zero additional proposals for new SNSs to specify DEX allocations.
  • Better security: Transparent treasury management with a fully on-chain audit trail.
  • Transparency: Improved visibility for SNS owned assets, e.g., to indicate DAO health.

Next Steps

  • Prototype the Liquidity Pool Extension and refine the design.
  • Share the resulting prototype and detailed design with the community.
  • Extend the SNS API to support registering Liquidity Pool Extensions.

We’re committed to building a robust and user-friendly SNS Liquidity Pools feature that will benefit the entire ecosystem, including the SNS communities and DEXs. Please share your feedback on this high-level design to facilitate the discussion.

20 Likes

Yes, this is brilliant. Will have a more in-depth read later.

The critical part is that the CreateSNS call has the initial liquidity parameters. The aim here is to stop situations like ICPex, Fomo, Estate, FuelEV, where the tokens are artificially withheld from dexes to make it impossible to compete with the dev team.

This discrepancy in tokens is made even worse by gaming the age bonus so that by the time you’ve managed to get a decent stake, the initial dev neuron stake has grown (Alice for instance.)

8 Likes

Nice!This is a great approach, especially if the liquidity ratio can be determined at the early stage of SNS creation.

When will the feature go live?

Would it be possible to extend this to any ICRC-1 tokens? Such that a DAO could have a pair between their governance token and USDC, or their governance token and nICP.

1 Like

The critical part is that the CreateSNS call has the initial liquidity parameters …

… the liquidity ratio can be determined at the early stage of SNS creation

Indeed; I think good UX and and security are very much aligned in this case.

When will the feature go live?

The timeline is not yet fully defined, but this feature is a high priority for the Governance team right now, and we’re going to share the ETAs very soon. Stay tuned!

Would it be possible to extend this to any ICRC-1 tokens? Such that a DAO could have a pair between their governance token and USDC, or their governance token and nICP.

Great question; as you know, the SNS currently doesn’t officially support such tokens (apart from its native token and ICP), but we know there’s demand for it, and we’re looking into how to best support them. I don’t know yet whether this will be part of the first SNS Liquidity Pools feature, or maybe a follow-up.

I will say though, that the API we’re designing for the Liquidity Pool Extension canister is going to support arbitrary tokens in the ICP ecosystem (most likely, we will require the ICRC-1,2,3 standards).

More details will follow.

4 Likes

Dear @aterga and DFINITY Team

Thanks so much for all your great work!

After several rounds of discussion, it’s clear that implementing the SNS Liquidity Pool Extension via proxy canisters is the most suitable and scalable approach.

We fully support this initiative, as it streamlines the liquidity provision process and significantly improves the trading environment for SNS tokens.

Three quick questions:

  1. Will each SNS DAO need to create and manage its own dedicated Liquidity Pool Extension canister, including monitoring and topping it up with cycles?

  2. Once liquidity is added via the Liquidity Pool Extension, is it managed directly by the extension canister, or does control remain with the SNS DAO’s Governance Canister?

  3. If an SNS DAO later wants to adjust its liquidity settings, can it flexibly do so via the extension canister?

Thanks a lot!

3 Likes

Sounds fantastic! I’m very much looking forward to seeing this sort of thing.

Given that these canisters will be about streamlining (and to some extent standardising) SNS integration with DEXs, it would be absolutely wonderful if you would consider making it easy for an SNS to establish an automated buy-back-and-burn mechanism via these canisters (helping to abstract away dex-specific details).

This would make it easy to launch SNSs with deflationary governance tokens, potentially facilitating SNSs to configure higher staking rewards (improving SNS governance incentives).

In an example setup, an SNS could stake part of the ICP recieved from the decentralisation swap in an NNS neuron. Maturity from that neuron could feed perpetual buying and burning of the SNS governance token. This is of course already possible, but making it easy to be DEX-agnostic would be great!

3 Likes

Surely cICP would be a better choice due to the superior design.

3 Likes

@aterga

We express our strong support for the proposed SNS Liquidity Pool Extension.

It is evident that many SNS projects face a common challenge: even after launch and token distribution, a lack of standardized and streamlined liquidity provisioning mechanisms often results in SNS tokens remaining illiquid for extended periods. We believe this proposal is well thought out, balancing security, scalability, and maintainability.

As a core DEX infrastructure provider in the Internet Computer ecosystem, ICPEx fully embraces the direction of this proposal and is willing to collaborate with the Foundation and other DEX development teams to jointly advance the development of liquidity pool extension canister standards, SDK testing, and cross-DEX integration.

Meanwhile, we have completed the new architecture for ICPEx, supporting 2-second high-speed trading, multi-path routing, and MCP services. The platform’s core code has also been open-sourced and is available for public access:

https://next.icpex.org

If there is any related working group or discussion forum organized by the Foundation, we would be eager to join and contribute to the standardization of liquidity mechanisms within the SNS protocol.

Can’t imagine how it will work yet in detail, but it sounds great. I guess the main benefit here is the observability.
It will need to allow different types of liquidity provision inside one extension, if a DEX has multiple algorithms for that. I guess also, the configuration of existing positions, for example, moving a range.
I suppose in the future, part of the ICP from an SNS swap will go directly into a liquidity pool instead of treasury, and it will require a critical proposal to remove it.

2 Likes

Long needed feature - there should never be a situation where an SNS Swap completes & the end user has to wait to see if the DAO will come to consensus & prioritize liquidity provision.

3 Likes

I like that the goal here is to make defi liquidity more manageable for SNS’s. My understanding from the outline above is that you’re basically creating a standard for “SNS token/ICP” liquidity pool canisters that DEX’s and SNS’s can agree to build with. Please correct me if I misunderstood that, but I have some thoughts/ideas to share.

Could(or should) this be done in a way that allows for liquidity to be aggregated? This could improve pricing for swaps on the token pairs but also remove some arbitrage opportunities in the market which are created by the usual fragmentation. i.e. A single liquidity pool under the direct control of the SNS DAO with the right set of exposed endpoints for granting defi permissions to DEX’s.

1 Like

Yes; since we’re leaning towards making the Liquidity Pool Extension canister part of the DAO, it makes sense that the DAO is responsible for its canisters. We will provide tooling to simplify the key user journeys, e.g., deploying and upgrading the extension.

It would be managed directly, but all tokens that cannot be allocated int he DEX right away would be returned to the SNS treasury account (which is controlled by SNS Governance).

To some extent, yes. For example, the extension will support topping up liquidity. If you think some other adjustments are essential to support from the beginning, please speak up.

1 Like

Thank you so much for the detailed explanation.

From our role as both the SNS project team and the DEX, here’s our perspective on the third point you mentioned:
● Adding liquidity: :white_check_mark:

● Increasing liquidity: We can submit another Add Liquidity proposal to provide more liquidity. However, would this result in multiple positions that are difficult to manage? Or is it possible to add more liquidity to the existing position instead?

● Removing liquidity: There should be a corresponding proposal for removal, and the liquidity tokens would then be returned to the SNS treasury from the SNS Liquidity Pool Extension canister, correct? Also, is it possible to remove only a portion of the liquidity—say, 50%—by specifying a parameter?

● Adjusting the price range: This might be achieved by combining a remove liquidity proposal with a new add liquidity proposal.

● Claiming LP fees: Would this require a separate proposal?

1 Like

Hi @ICPSwap,

Thank you so much for the detailed explanation.

Thank you too for your interest and the good questions.

would this result in multiple positions that are difficult to manage? Or is it possible to add more liquidity to the existing position instead?

The latter; it will be possible to top up an existing position using subsequent deposit operations.

Removing liquidity: There should be a corresponding proposal for removal, and the liquidity tokens would then be returned to the SNS treasury from the SNS Liquidity Pool Extension canister, correct?

Agreed. There will be a withdraw operation. It will send as much as possible back to the SNS treasury.

is it possible to remove only a portion of the liquidity—say, 50%—by specifying a parameter?

This is generally problematic, as we would need a way to specify the amount. Intuitively, 50% seems clear, but imagine that an SNS has a proposal to withdraw 50%. Is that 50% of the assets at the time of proposal submission, or at the tie of proposal execution (which could be a few days later, a potentially very different value)? The community needs to know what exactly they are voting for, and we currently don’t have a clear way to specify this intention.

In the next iterations of the feature, the LP extension might gain the ability to withdraw specific amounts when specific conditions occur. This would not require proposals, as it would be 100% automated by the smart contract. Until then, I think even without partial withdrawal, this feature would already add value to the community. Would you agree?

Adjusting the price range: This might be achieved by combining a remove liquidity proposal with a new add liquidity proposal.

Sounds interesting, but could you clarify on a simple example how this could work?

Claiming LP fees: Would this require a separate proposal?

For DEXs that support rewards, those should be sent back to the SNS treasury automatically on a regular basis. Full withdrawal will, of course, also take rewards / LP fees into account.

1 Like

Update on the Liquidity Pool extension.

  • The Governance team drafted an API that serves the purpose of SNS LP extensions. Please feel free to review it here.
  • We call this the Treasury Manager API, as it is not specific to liquidity pools and DEXs, and could also be used for other implementations and SNS Treasury Manager canisters.
2 Likes

Hi @aterga !
I have read the description and the draft code of the treasure manager. Here are several questions, please help answer them:

  1. Regarding audit_trail, there is only one TreasuryManagerOperation in a Transaction. Should we change it to save an array instead, as some transactions require several operations and steps.
  2. Do deposit, withdraw, refresh_balances and audit_trail have to be strictly implemented according to the interface definition? Especially for deposit and withdraw, are they the default SNS methods or do they require the project party to register as SNS methods. If customization requires, how can we ensure that all project parties use the same standards for development. Can the official at least unify the code for deposit and withdraw, or can the code for defining interfaces be uniformly implemented by the official?
  3. Do we need to set the fee_collector every time we deposit, and do we need to customize the charging mechanism for fee_collector?
  4. Between deposit and adding liquidity, there needs to be some more operations between the treasure manager and DEX. In this case, the treasure manager needs to call DEX multiple times. How to trigger this interaction, should we use SNS voting to trigger it, or can we add permission management functionality for the treasure manager, where a trusted address added by the accompanying voting can call the interface.
  5. What is the logic of the automatic return of assets by the treasure manager. Is it to verify whether there are any assets left after adding liquidity each time, and if there are any, to automatically return them?

Thanks a lot!

2 Likes

Hi @HeliosFz, thanks for looking into the proposed API and asking good questions.

  1. Regarding audit_trail, there is only one TreasuryManagerOperation in a Transaction. Should we change it to save an array instead, as some transactions require several operations and steps.

In the current API design, transactions in the audit trail correspond to calls to external canisters, i.e, they are low-level. The high-level information about which operation a particular transaction corresponds to is saved in the treasury_manager_operation field of a transaction. That’s why we have a 1:1 relationship between these two things. Here’s an example:

transactions = vec {
  record {
    treasury_manager_operation = {
      operation = Deposit;
      step = record {
        index = 0;
        is_final = false;
      };
    };
    ...
  };
  record {
    treasury_manager_operation = {
      operation = Deposit;
      step = record {
        index = 1;
        is_final = true;
      };
    };
    ...
  };
};

Here, the (high-level) operation is called Deposit, and it includes two steps, each of which is a (low-level) transaction.

  1. Do deposit, withdraw, refresh_balances and audit_trail have to be strictly implemented according to the interface definition?

Short answer, yes. See below for more details.

Especially for deposit and withdraw, are they the default SNS methods or do they require the project party to register as SNS methods.

When an SNS registers an extension, the update methods of the extension become callable via an SNS proposal. The governance team is working on a simple new mechanism that would make this possible without having to register custom proposals for each extension operation. Rather, these operations will become available right after the extension is registered. (Their topic and criticality will be determined by the extension’s specification, known at the time when the NNS decides to allow a new kind of extension, and visible to the voters).

If customization requires, how can we ensure that all project parties use the same standards for development. Can the official at least unify the code for deposit and withdraw, or can the code for defining interfaces be uniformly implemented by the official?

I agree that some unification would be nice, and the Treasury Manager API (and the first reference implementation; see below) is the starting point. Note that, e.g., existing DEXs have completely different architectures, so there would need to be a lot of customization for Treasury Manager implementations targeting those DEXs.

More details about the Treasury Manager API

The SNS framework will be able to call a Treasury Manager (e.g., a DEX liquidity provider implementation) as an external canister using its public Candid API. This means that the implementation isn’t relevant to the SNS (so long as it has passed the in-depth reviews necessary for it to be allowed by the NNS).

That being said, the Governance team is building a reference implementation in a way that other developers could use as a concrete template for building other Treasury Manager instances. (It happens to be in Rust, and the code is already public. If there’s anyone who would like to build a reference Motoko implementation, that could be very interesting.)

Feedback on the reference implementation(s) is also welcome!

  1. Do we need to set the fee_collector every time we deposit, and do we need to customize the charging mechanism for fee_collector?

Yes to the former, and no to the latter. Specifying the fee explicitly would cause a deposit to fail if the fee changes during the voting period. This is to mitigate the following attack vector:

A Treasury Manager can operate on assets based on various different ledgers. For example, if the reference implementation, we’re dealing with ICP and the SNS ledger of the SNS that owns the managed assets. However, we don’t rule out the case that a Treasury Manager could manage assets from an “external” ledger, i.e., one that is not under the control of this DAO and does not already have as much credibility as ICP (think, a ledger of another SNS). The controllers of such a ledger could attack the Treasury Manager by raising the fee to an unfair amount (which could be done even temporarily, and it’s well-known when this would need to take effect, since the Treasury Manager operations are behind SNS proposals that might have an easily predictable voting period).

Concretely, we don’t want an SNS community to agree to deposit, e.g., 1000 ABC tokens / 1000 ICP, as DEX liquidity, assuming that the fees would be negligible, only to observe that the actual amount of ABC tokens added was 100 ABC (and 900 ABC was payed out as a ledger fee).

  1. Between deposit and adding liquidity, there needs to be some more operations between the treasure manager and DEX. In this case, the treasure manager needs to call DEX multiple times. How to trigger this interaction, should we use SNS voting to trigger it, or can we add permission management functionality for the treasure manager, where a trusted address added by the accompanying voting can call the interface.

The SNS voting would trigger each of these flows, e.g., a single SNS proposal to deposit. The rest (e.g., ensuring that the right tokens are registered in the DEX, calling the Ledger to set required allowances, etc.) needs to be implemented by the Treasury Manager smart contract.

Here’s my reasoning: It is in the best interest of the SNSs to keep all these operations fully on-chain. To that end, we are removing the need for any trusted 3rd parties (to be clear, an SNS using a Treasury Manager in its current design would need to trust itself as a DAO, the NNS, and possibly, an external custodian it wants to cooperate with, e.g., a DEX, and no one else).

  1. What is the logic of the automatic return of assets by the treasure manager. Is it to verify whether there are any assets left after adding liquidity each time, and if there are any, to automatically return them?

Yes - you correctly identified one of the reasons to have a periodic refund tasks in a Treasury Manager.

Other reasons include: sending back rewards that an external custodian (e.g., a DEX) might have automatically sent to the Treasury Manager’s account; refunding after a previously unsuccessful withdraw attempt finally succeeded.

Please let me know if you have further questions.

2 Likes

Thank you @aterga ! Some more questions here:

In this case, the steps of operations from multiple different deposits may be the same. Is the field identifying which deposit the operation belongs to ‘purpose’, or does it require adding a new field?

So the deposit method is not simply transferring assets to the treasure manager, but directly recharging assets into DEX, right?

I still don’t understand the meaning of fee_collector. Is it just a transfer fee for tokens, or does it need to be paid as a management fee to the treasure manager? What is the charging mechanism?

So adding liquidity and other business logic needs to be written as SNS methods, and then registered by the project party into SNS, right?

Timed refunding means that there will be no fund accumulation in the treasure manager, right? Is the triggering frequency customized?

1 Like