Saturn Liquidity Pools

Introduction

Saturn is a decentralized exchange (DEX) that facilitates atomic swaps and liquidity provision directly on the base layer of Bitcoin. By leveraging the Arch Network's virtual machine and decentralized verifier network, Saturn eliminates the need for bridging assets or relying on secondary layers. This innovation brings advanced trading functionalities to Bitcoin while maintaining its core principles of decentralization and security.

The Problem with Trading Runes currently

Trading Rune tokens on the main layer of Bitcoin currently involves several methods, each presenting distinct trade-offs concerning user experience, decentralization, and transactional friction. This section examines the primary mechanisms by which applications have enabled the fungible trading of Bitcoin-based tokens prior to the introduction of Saturn Liquidity Pools.

Peer-to-Peer UTXO PSBT Marketplaces

The most widespread method for trading Bitcoin tokens is through peer-to-peer marketplaces that utilize Unspent Transaction Outputs (UTXOs) and Partially Signed Bitcoin Transactions (PSBTs). In these "NFT-style" marketplaces, users partially sign a transaction to sell an entire UTXO containing a specified amount of Rune tokens in exchange for Bitcoin.

Advantages

  • Trustless Transactions: This method operates without the need for trust between trading parties. The security and integrity of transactions are ensured by the Bitcoin network's consensus mechanism.

Disadvantages

  • Bulk Quantity Constraints: Users are required to sell Rune tokens in batch quantities dictated by the specific UTXO they wish to sell. This often leads to unintentional batch sizes, contributing to an inconsistent token supply and rendering the market semi-fungible.

  • Complexity for Novice Users: The necessity to understand and manage UTXOs can be confusing for new users. Associating specific amounts of Rune tokens with individual UTXOs adds an additional layer of complexity.

  • Limited Transaction Participants: The peer-to-peer nature of this method restricts transactions to two parties, which can hinder liquidity and limit market dynamics.

  • Susceptibility to Mempool Sniping: Transactions are vulnerable to front-running due to their exposure in the mempool, posing risks to users attempting to execute trades.

  • Lack of Advanced Trading Features: Users are unable to place open limit orders or have their orders partially filled, restricting trading flexibility and efficiency.

Custodial/Centralized Solutions

Another common method for trading Bitcoin tokens involves third-party custodial services managing user assets. This approach is exemplified by centralized exchanges like OKX, which facilitate Bitcoin token trading through their platforms. Additionally, some applications built on Bitcoin Layer 1 employ custodial solutions to offer liquidity pools for Bitcoin tokens.

Advantages

  • Frictionless User Experience: Centralized exchanges provide a seamless and intuitive trading environment. Token trading is fully fungible and straightforward, making it accessible even to users with minimal technical knowledge. This ease of use extends to on-chain custodial liquidity pools, where the trading process remains user-friendly.

Disadvantages

  • Trust Dependency: Users are required to place trust in the custodians managing their assets. This reliance introduces significant risk, as users do not have direct control over their private keys. High-profile failures, such as the collapse of FTX, highlight the potential dangers of entrusting assets to third parties, despite regular audits and regulatory oversight.

  • Lack of Contribution to Miner Fees and Network Support: Centralized exchanges typically conduct trades off-chain, meaning they do not execute transactions on the Bitcoin base layer. As a result, they do not contribute to miner fees, which are crucial for incentivizing miners and maintaining network security. This omission raises concerns among the Bitcoin community about the sustainability of the network's security budget.

Base Layer Multi-Signature Trading Wallets

An alternative method for trading Bitcoin tokens on the base layer involves the use of multi-signature (multi-sig) trading wallets. This approach employs a network of multi-sig wallets that can trade with one another in a more fungible environment. It ensures that users retain full control over their funds while providing a frictionless trading experience and contributing to the network through transaction fees.

Advantages

  • Frictionless User Experience: The trading experience using multi-sig wallets is streamlined and user-friendly, akin to trading on platforms like Ethereum. Users benefit from a seamless interface that simplifies token transactions on the Bitcoin network.

  • Advanced Trading Functions: The additional verification steps enabled by multi-sig wallets allow users to safely participate in open orders and have their orders partially filled. This capability introduces advanced trading features to the Bitcoin base layer, enhancing flexibility and efficiency.

  • Mempool Sniping Resistance: Since the network of multi-sig wallets interacts exclusively with other multi-sig wallets within a designated database, miners are unable to access open orders or engage in malicious activities such as front-running. This isolation enhances the security of transactions against mempool vulnerabilities.

  • Support for Multiple Counterparties: The system allows for the involvement of an unlimited number of wallets in a single trade, facilitating more complex transactions. This feature enhances fungibility and enables more sophisticated trading strategies by accommodating multiple counterparties.

Disadvantages

  • High Transaction Friction: Users are required to deposit funds into a multi-sig wallet on the base layer. Although this method is non-custodial, the necessity to deposit and withdraw from a trading wallet introduces significant friction. Additionally, it involves at least two transactions, which can be costly due to transaction fees. This level of friction is comparable to using a Layer 2 solution but without the associated scalability benefits.

  • Siloed Liquidity: Because users can only interact with other multi-sig wallets within the specific database, they are not exposed to the broader global liquidity pool. This isolation, combined with the inherent friction of the system, results in a less liquid trading environment. The reduced liquidity can lead to suboptimal trading conditions and wider bid-ask spreads.

Benefits of the Saturn Approach

Saturn addresses the limitations of existing methods by introducing a novel approach that brings advanced DeFi functionalities to Bitcoin's base layer without compromising its core principles.

  • Turing Complete Smart Contracts Natively on Bitcoin: By leveraging the Arch Network Virtual Machine and Decentralized Verifier Network, Saturn enables complex computations directly on Bitcoin's base layer without the need to wrap assets or bridge to another chain.

  • Atomic Swaps: Facilitates trustless and efficient asset swaps with guaranteed execution, enhancing security and reliability.

  • Secure Non-Custodial Liquidity Provision: Allows users to provide liquidity and earn fees in a non-custodial manner, maintaining control over their assets.

  • Simplified User Experience: Removes the need for bridging assets or interacting with multiple blockchains, making decentralized trading more accessible.

  • Pools for Lending Liquidations: Saturn's liquidity pools can support lending protocols by enabling decentralized, non-custodial liquidations. When collateral falls below the required threshold, liquidations are executed through Saturn’s pools, ensuring efficient and trustless liquidation processes while maintaining liquidity for lenders.

Maximal Extractable Value (MEV)

Protecting our users from potential value extractions by miners, marketplaces, or mempool snipers is paramount. Maximal Extractable Value (MEV) issues are prevalent in current marketplaces, but Saturn has developed strategies to minimize these problems significantly. Before explaining our solution, it's important to understand the MEV challenges in existing marketplaces.

MEV in Current Solutions

Peer-to-Peer UTXO PSBT Marketplaces

The primary MEV issue in current NFT marketplaces is front-running, commonly referred to as mempool sniping. When a user sells Rune tokens, they generate a Partially Signed Bitcoin Transaction (PSBT) with an input and output specifying the amount of Rune tokens being exchanged for Bitcoin. This transaction is signed using SIGHASH_SINGLE | ANYONECANPAY, which allows anyone to modify the transaction by adding or changing inputs or outputs until it is confirmed on the Bitcoin network. Opportunistic actors—such as miners or other users—can intercept this transaction in the mempool and create a new version with a higher fee, effectively front-running the original transaction. Miners, incentivized by the higher fee, will prioritize this new transaction, bypassing the original and exploiting the user’s trade.

This creates a vulnerable window, approximately 10 minutes on average (the time it takes to confirm a block on Bitcoin), during which anyone can exploit arbitrage opportunities on that token. The user who initially signed and broadcasted the transaction is left powerless unless they engage in a bidding war, raising network fees to outbid potential snipers.

Centralized Liquidity Pools

In custodial solutions such as centralized liquidity pools, the program's address is controlled by a multisignature (multisig) wallet. This wallet is typically managed by one or several entities, creating what is known as a dark pool—where the actual liquidity is opaque and unknown to users. Users are further exposed to sandwich attacks, where the multisig manager can reorder transactions to their advantage, manipulating prices to the detriment of regular users.

How Saturn Solves MEV Issues

Saturn has developed mechanisms specifically designed to minimize MEV risks while ensuring transparency and user security:

  • BTC to Rune Swaps: For this type of swap, users sign transactions using SIGHASH_ALL, which eliminates the possibility of mempool sniping. Once the transaction is broadcast to the Bitcoin network, it becomes final, and no arbitrage or front-running is possible.

  • Rune to BTC Swaps: While this type of swap could be susceptible to mempool sniping due to the SIGHASH_SINGLE | ANYONECANPAY signature, Saturn mitigates this risk through collective protection. When users trade within the same liquidity pool, they modify the pool’s account and corresponding UTXO. Multiple users trading with the same pool reuse the output from the previous transaction by leveraging the Child Pays for Parent (CPFP) mechanism (explained in the following section). This means that a mempool sniper would not only be competing with the original user but also with all other users interacting with the pool, drastically reducing the likelihood of a successful snipe.

  • Transparency and Non-Custodial Pools: Unlike centralized liquidity pools, Saturn’s pools are entirely non-custodial, meaning users maintain control of their assets at all times, and the liquidity in each pool is fully transparent. This ensures that any user can verify the liquidity of each pool, eliminating the opacity associated with dark pools. Moreover, Saturn’s architecture ensures that, unlike custodial solutions, we cannot reorder transactions for our benefit or manipulate the execution of trades. This transparency and inability to interfere with transactions provide a significant security advantage over custodial liquidity solutions.

  • Verifiable Transaction Order in Arch Network: On the Arch Network, the leader validator processes transactions on a first-in, first-out (FIFO) basis, ensuring they are handled in the order they arrive. To further minimize the possibility of MEV attacks, Arch is working on implementing a Verifiable Delay Function (VDF), similar to Solana’s Proof of History (PoH). This function will make it cryptographically provable that transactions are processed in the correct order, adding an additional layer of protection against manipulation and ensuring that the transaction order cannot be altered, even if someone tries to modify the validator. This mechanism minimizes MEV risks to the greatest extent possible.

By ensuring transactions are interconnected, transparent, and secure, and by leveraging collective user protection, Saturn effectively minimizes MEV risks—including mempool sniping and other forms of value extraction—while providing a robust, transparent trading environment.

Understanding Arch Network Concepts

Before delving into the details of our program, it's essential to understand some fundamental Arch concepts that influenced our technical decisions.

State Storage in Arch

In Arch, the state is stored on the network—for example, the open positions of each liquidity provider and their values are kept in Arch. This approach offers a significant advantage as storing information in Arch is significantly cheaper and therefore sustainable, rather than storing it on Bitcoin. However, this raises a critical question: How do we ensure that the state of Arch and Bitcoin remain synchronized?

Consider a scenario where a Bitcoin transaction is sent to perform a swap of Bitcoin for UNCOMMON*GOODS. The contract's state is updated, and the transaction is issued on Bitcoin. However, if the user decides to use the same UTXOs (Unspent Transaction Outputs) used for the swap transaction for a different transaction with a higher fee rate, miners will discard the swap transaction in favor of the one with the higher fee. This situation leads to a synchronization problem between Arch and Bitcoin because Arch would believe the transaction occurred, altering the token balances, while in reality, it did not.

Ensuring State Synchronization

To solve this, we link each Arch account to a UTXO on Bitcoin. Every time we create an account in Arch, a UTXO must be sent to the account's address on Bitcoin. To modify the account's state, we need to spend the UTXO from that address and generate a new UTXO that returns to the same address. This process ensures that if, for some reason, a transaction is not confirmed on Bitcoin or is rejected by miners, the state will not update in Arch.

In practice, we chain transactions where each subsequent transaction consumes the UTXO generated by the previous one, continuously using what is known in Bitcoin as CPFP (Child Pays for Parent). The significant drawback of this system is that Bitcoin imposes a constraint: there cannot be more than 25 unconfirmed transactions that use CPFP. This limitation means an Arch account cannot be modified more than 25 times. This constraint poses a significant limitation if we aim to build a DeFi ecosystem on Bitcoin. How can trading occur if one can only interact with a liquidity pool 25 times per block? With an average of 10 minutes per block, we could have about 25 transactions every 10 minutes, or 2.5 transactions per minute, which is insufficient for a functional trading system.

Overcoming Bitcoin's Limitations

We address this issue by dividing the state into multiple accounts and reconstructing the pool's state from these accounts whenever we call the contract. This approach allows us to read from all accounts to rebuild the pool's state but only write to one account, thereby increasing the pool's transactions per second (TPS) without hitting Bitcoin's transaction constraints.

Our initial idea is to have about 50 shards (accounts) per pool, which means we could have up to 1,250 transactions per pool per block. Considering that an average Bitcoin block has about 3,000 transactions, a single pool could occupy approximately 41% of a block. These numbers are more acceptable for enabling DeFi on Bitcoin. The number of shards per pool can be increased in the future if necessary.

Saturn Liquidity Pools

Saturn implements Uniswap V2-style liquidity pools. While we won't delve into explaining what these pools are or how they function—you can find a detailed explanation in this whitepaper—we will focus on our implementation and how we've navigated the various limitations of Arch and Bitcoin.

Pool State

The first significant challenge is defining the pool's state. A liquidity pool has a relatively simple state, which can be defined with the following struct:

pub struct LiquidityPool {
    /// Total liquidity in pool
    pub total_supply: u128,

    /// Fee rate stored as hundreths of a basis point
    /// u16::MAX (65_535) corresponds to ~6.5%
    /// A fee rate of 0.3% would be stored as 3000
    pub fee_rate: u16,

    pub fee_to: Option<Pubkey>,

    pub protocol_fee_owed: u128,
    pub protocol_fee_paid: u128,

    /// Id for token 0
    pub token_0_id: Token,

    /// Id for token 1
    pub token_1_id: Token,

    /// Balance for token 0
    pub reserve_0: u128,

    /// Balance for token 1
    pub reserve_1: u128,

    /// Last recorded price
    pub k_last: BigInt,
}

We could store this state in an account in Arch, but we would face the 25 transactions per block limitation mentioned earlier. Therefore, we divided the state into multiple accounts, and each time we call the contract, we reconstruct the pool's state from these accounts. This method allows us to read from all accounts to rebuild the pool's state but only write to one account, minimizing the Bitcoin transaction cost and avoiding using any of the shards more than 25 times per block.

Splitting the State

We divided the state into several parts:

Pool Configuration Account

This account details the initial configuration of the pool. It is modified only when the pool is first created and specifies the tokens that make up the pool, the number of shards the pool will have, and the fees that liquidity providers will receive.

pub struct LiquidityPoolConfig {
    pub fee_rate: u16,
    pub fee_to: Option<Pubkey>,
    pub shards: usize,
    pub token_0: Token,
    pub token_1: Token,
}

Shards

We have a series of shards per pool, which is where we store most of the state.

pub struct LiquidityPoolShard {
    pub pool_pubkey: Pubkey,
    pub rune_utxo: Option<UtxoInfo>,
    pub btc_utxos: Vec<UtxoInfo>,
    pub liquidity: u128,
    pub protocol_fee_owed: u128,
    pub protocol_fee_paid: u128,
    pub last_block_height: u64,
    pub times_updated: u128,
}
pub struct UtxoInfo {
    pub utxo: UtxoMeta,
    pub value: u64,
    pub runes: Vec<RuneAmount>,
}

From the shards and the configuration account, we can reconstruct the pool's state by summing the liquidity issued in all shards and the amount of each token we have in the UTXOs of each shard. Each time we call the contract, we must pass the 51 accounts but only modify those necessary, minimizing the Bitcoin transaction cost to the minimum and always trying not to use any of the shards more than 25 times per block.

Liquidity Position Accounts

Lastly, we have one account per liquidity position. Each user can open a position per liquidity pool. When a user adds or removes liquidity from the pool, this position is modified.

pub struct Position {
    /// Pool pubkey
    pub pool_pubkey: Pubkey,

    /// Address of the owner
    pub owner: Pubkey,

    /// Liquidity in this position
    pub liquidity: u128,
}

Feeding the Program with Off-Chain Information

Another significant challenge we faced is how to feed the program with the number of runes a UTXO has. In Arch, we can obtain the hex of the transaction and, therefore, know how much Bitcoin is in each output of the transaction. However, with the transaction hex, we cannot know for certain how many runes each output has. Therefore, we've had to create an on-chain oracle to provide this information to the network so we can call this oracle from the contract to obtain the exact number of runes in each UTXO.

Instructions

Initialize pool

Initializing the pool involves creating the accounts where the state will be stored. These accounts, as mentioned earlier, are linked to UTXOs. Therefore, for each account we want to create, we need to send a UTXO to the account's address.

In this context, the user must create a transaction that has 51 UTXOs (one UTXO for the pool's configuration and another 50 UTXOs for the shards) that are sent to the program's address.

Once the transaction has been issued, we create a message that is sent to the Arch network. In this message, we specify the pair of tokens with which we want to create the pool (always one of them must be Bitcoin), as well as various configurations like the pool's fee tier.

pub struct InitializePoolInstruction {
    pub utxos_info: Vec<UtxoInfo>,
    pub params: InitializePoolParams,
}

pub struct InitializePoolParams {
    /// The trading fee that is incurred during swaps, in basis points
    pub fee: u8,
    /// Id of the rune that will be held in this pool
    pub token_0: Token,
    // Always BTC
    pub token_1: Token,
}

This diagram summarizes what happens on the Bitcoin network:

  1. The user signs and emits the first transaction to the network.

  2. Upon calling the Arch program, Arch emits the second transaction, initializing the accounts in Arch and linking them to their respective UTXOs in Bitcoin.

Open Position and Increase Liquidity

When a user wants to provide liquidity, they must create a transaction where they send a UTXO with the amount of runes they want to contribute and another UTXO with the amount of Bitcoin they want to contribute. Additionally, in the Bitcoin UTXO, they must include the fees required to pay for the state change transaction.

Similarly to initializing the pool, once they have sent the assets to the program's address, the user creates a message in Arch with the list of UTXOs they have added.

pub struct OpenPositionInstruction {
    pub utxos_info: Vec<UtxoInfo>,
}

The program will validate that the specific user has indeed added liquidity to the pool, and if so, it will create the transaction for the state change, where it creates the position account and adds the liquidity to one of the pool's shards, as shown in the following illustration:

Note: We deduct the transaction fees from the user's BTC, so only the actual BTC added to the pool as part of the liquidity is considered.

Future improvement:

We are currently working on an improvement to this which will prevent slippage when adding liquidity

Decrease Liquidity

To withdraw liquidity from their position, the user must create a message that is sent to the Arch network. In this message, the user specifies the liquidity they want to withdraw, the slippage, and the addresses where they want to receive each token. Optionally, they can include a transaction to pay for the fees of the transaction, but the contract will attempt not to use it and instead use the Bitcoin being withdrawn to pay for the transaction fees.

pub struct DecreaseLiquidityInstruction {
    pub params: DecreaseLiquidityParams,
}

pub struct DecreaseLiquidityParams {
    // Amount of liquidity to withdraw
    pub liquidity_amount: u128,

    /// Min ammount of token a and b to withdraw (acts as slippage)
    pub min_token_0: u128,
    pub min_token_1: u128,

    pub withdraw_address_token_0: String,
    pub withdraw_address_token_1: String,

    /// A Transaction signed by the caller containing a UTXO for transaction fees.
    /// It's optional because the fees can be covered by removing liquidity from
    /// the pool.
    pub transaction: Option<Vec<u8>>,
}

The final transaction that the pool will emit to the Bitcoin network would look like this:

Atomic Swaps

Saturn enables atomic swaps in both directions—Rune to BTC and BTC to Rune. These swaps allow users to exchange assets in a decentralized and trustless manner, with guaranteed execution. Below is an explanation of how each swap works, including the required steps and details about the transactions involved.

Rune to BTC Swap

In a Rune to BTC swap, the user must sign a transaction that specifies the exact amount of Rune tokens they wish to swap and the amount of Bitcoin they expect to receive. Here's a breakdown of the process:

  1. Transaction Setup: The user creates a transaction with an input specifying the amount of Rune tokens to be swapped and an output for the Bitcoin they want to receive. It's crucial to account for the transaction fee—meaning the user must subtract the fee from the total Bitcoin they expect to receive. The user signs the transaction using SIGHASH_SINGLE | ANYONECANPAY, similar to how transactions are signed in NFT marketplaces.

  2. Slippage Handling: In this case, the slippage is embedded in the Partially Signed Bitcoin Transaction (PSBT) that the user signs. By signing the input/output pair, the user agrees to receive at least a minimum amount of Bitcoin, which serves as a buffer for price fluctuations (slippage). This approach ensures the swap will not be completed unless the user receives the expected amount or more.

  3. Contract Verification and Execution: Once the user submits the transaction, the contract verifies that the amount of Rune tokens and Bitcoin are within the slippage limits. If everything is correct, the contract finalizes the transaction by adding its inputs and outputs. If the user is entitled to more Bitcoin than expected (due to favorable price movements), the contract will automatically create an additional output to send the remaining Bitcoin to the user.

  4. Final Transaction: The final transaction emitted to the Bitcoin network includes the input from the user, the necessary contract inputs, and any additional outputs if applicable.

Details of both transactions—the one the user signs and the final one emitted to the network—can be found in the following diagram:

Runestone Data in Rune to Btc Swap

In this type of swap, the only information we need to specify in the runestone is the output where we want all the Rune tokens from the inputs to go. This is done by simply specifying the output index in the pointer and leaving the rest of the runestone values undefined.

{
    "pointer": 2,
}

This ensures that the Rune tokens are directed to the correct output during the swap.

BTC to Rune Swap

A BTC to Rune swap is more complex than the Rune to BTC swap, as it requires the user to specify all transaction outputs in advance. The steps are as follows:

  1. Transaction Setup: The user needs to prepare a more detailed transaction because they will sign using SIGHASH_ALL | ANYONECANPAY. In this case, they must include:

    • Bitcoin Inputs: All the Bitcoin inputs the user is contributing to pay for the Rune tokens they wish to obtain.

    • Transaction Outputs:

      • One or more outputs corresponding to the accounts in the pool they wish to modify.

      • An output to allocate the remaining Rune tokens in the pool.

      • An output for the user to receive their Rune tokens.

      • An output for the OP_RETURN of the runestone.

      • An output where the user sends Bitcoin in exchange for the Rune tokens.

      • Optionally, an output where the user receives the change from their Bitcoin contribution if it exceeds the cost of the runes.

      • Optionally, an output for frontend fee can also be specified if applicable.

  2. Contract Inputs and Execution: Once the user submits the signed transaction, the program verifies the details and includes the necessary Rune inputs for the swap if the values fall within the slippage parameters. The slippage buffer, like in the Rune to BTC swap, is embedded in the PSBT that the user signs. This ensures the transaction will only be executed if the user receives the correct amount of Rune tokens as specified in the runestone.

  3. Finalizing the Swap: After verifying and including the required inputs, the contract completes the transaction. This results in a final output that delivers the correct amount of Rune tokens to the user.

Runestone Data in BTC to Rune Swap

In this case, the runestone the user adds to the transaction is more complex. In the edicts, the user specifies the number of Rune tokens they want to receive in exchange for the Bitcoin they are sending to the program. Additionally, the user must ensure that any remaining Rune tokens from the inputs that are not used are returned to the program. This is done by specifying the output index for the program's address in the pointer.

{
    "pointer": 2,
    "edicts": [
        {
            "id": "0:0",
            "amount": XXXX
        }
    ]
}

This structure ensures that the user receives the correct amount of Rune tokens, while the remaining Rune tokens are allocated back to the pool.

Swap Instruction

The swap operation is executed by submitting the following instruction to the Arch network. The transaction that the user signs needs to be embedded into this message.

pub struct SwapInstruction {
    pub params: SwapParams,
    pub utxos_info: Vec<UtxoInfo>,
}

pub struct SwapParams {
    // Transaction that include the user's utxos to be swapped
    pub transaction: Vec<u8>,

    /// Direction of the swap. True if swapping from 0 to 1, false if swapping from 1 to 0
    pub zero_to_one: bool,

    /// Swap type: True if we want to swap that exact in value, false if we want to swap that exact out value
    pub exact_in: bool,

    pub frontend_fee: Option<FrontendFeeParams>,
}
pub struct FrontendFeeParams {
    pub address: String,
    pub fee: u64,
}

The SwapParams struct contains the details of the swap, including whether the swap is Rune to BTC or BTC to Rune (zero_to_one), and whether the swap is for an exact input or output value (exact_in). Optionally, a frontend fee can also be specified if applicable.

How We Avoid UTXO Bloating?

If you've noticed, in the BTC to Rune swap, one of the outputs is the amount of Bitcoin that the user sends to the program in exchange for the runes they acquire. This UTXO needs to be added to the pool, and thus, each time a user performs a BTC to Rune swap, a new UTXO is generated, causing the liquidity of our Bitcoin in the pool to spread among many UTXOs, increasing the cost of swaps.

To avoid this, in the BTC to Rune swap, we make the user pay an extra fee as if they were paying for an additional input at the current fee rate. Later, when a user performs an increase liquidity, we use that transaction to consolidate all Bitcoin UTXOs in one, using the extra fee paid by the user who performed the swap to cover the transaction fees. This way, although there might be more than one Bitcoin UTXO per shard at any given time, whenever any user adds liquidity to the pool, all Bitcoin UTXOs in a shard will be consolidated into one.

On the other hand, due to the way we create swap transactions, there will never be more than one UTXO for runes in the each shard, as we always consolidate the rune UTXO in swaps.

What's Next?

Rune to Rune Trading Is Possible

Currently, we only allow creating liquidity pools against Bitcoin, but imagine the possibility of trading on Bitcoin using a token pegged to the US dollar as the reference asset.

DEX Functionalities

Imagine being able to create buy or sell orders for tokens directly on-chain, similar to the OpenBook that exists today on Solana.

Last updated