DEV Community

yuzurush
yuzurush

Posted on • Updated on

Soroban Contracts 101: Batched Atomic Swaps

Hi there! Welcome to my thirteenth post of my series called "Soroban Contracts 101", where I'll be explaining the basics of Soroban contracts, such as data storage, authentication, custom types, and more. All the code that we're gonna explain throughout this series will mostly come from soroban-contracts-101 github repository.

In my previous post, i already explained about Atomic Swap contract, and in this post i will be explaining batched atomic swaps contract that matches and batches multiple swaps, whereas the atomic swap contract only handles a single swap.

The Contract

#![no_std]

use soroban_sdk::{contractimpl, contracttype, Address, BytesN, Env, Vec};

mod atomic_swap {
    soroban_sdk::contractimport!(
        file = "../target/wasm32-unknown-unknown/release/soroban_atomic_swap_contract.wasm"
    );
}

#[derive(Clone)]
#[contracttype]
pub struct SwapSpec {
    pub address: Address,
    pub amount: i128,
    pub min_recv: i128,
}

pub struct AtomicMultiSwapContract;

#[contractimpl]
impl AtomicMultiSwapContract {
    // Swap token A for token B atomically between the parties that want to
    // swap A->B and parties that want to swap B->A.
    // All the parties should have authorized the `swap` via `swap_contract`,
    // but they don't need to authorize `multi_swap` itself.
    pub fn multi_swap(
        env: Env,
        swap_contract: BytesN<32>,
        token_a: BytesN<32>,
        token_b: BytesN<32>,
        swaps_a: Vec<SwapSpec>,
        swaps_b: Vec<SwapSpec>,
    ) {
        let mut swaps_b = swaps_b;
        let swap_client = atomic_swap::Client::new(&env, &swap_contract);
        for acc_a in swaps_a.iter() {
            let acc_a = acc_a.unwrap();
            for i in 0..swaps_b.len() {
                let acc_b = swaps_b.get(i).unwrap().unwrap();

                if acc_a.amount >= acc_b.min_recv && acc_a.min_recv <= acc_b.amount {
                    // As this is a simple 'batching' contract, there is no need
                    // for all swaps to succeed, hence we handle the failures
                    // gracefully to try and clear as many swaps as possible.
                    if swap_client
                        .try_swap(
                            &acc_a.address,
                            &acc_b.address,
                            &token_a,
                            &token_b,
                            &acc_a.amount,
                            &acc_a.min_recv,
                            &acc_b.amount,
                            &acc_b.min_recv,
                        )
                        .is_ok()
                    {
                        swaps_b.remove(i);
                        break;
                    }
                }
            }
        }
    }
}

mod test;
Enter fullscreen mode Exit fullscreen mode

Here's an explanation of the AtomicMultiSwapContract contract:

  • It imports the atomic swap contract
  • It defines a SwapSpec struct to represent a single swap specification (address, amount to send, minimum to receive)
  • It defines an AtomicMultiSwapContract struct
  • It implements a contractimpl for AtomicMultiSwapContract with a multi_swap function
  • The multi_swap function:
  • Loops through swaps that want to send token A and swaps that want to send token B
  • Matches compatible swaps (where the send amount meets the minimum receive amount for the other party)
  • Calls the atomic swap contract's try_swap function to attempt the swap
  • Removes matched swaps from the list

The key point of this AtomicMultiSwapContract contract are:

  • This contract matches and batches multiple swaps
  • Parties only need to authorize the atomic swap contract, and don't need additional authorizations for the multi-swap
  • The AtomicMultiSwapContract contract calls the atomic swap contract to attempt individual swaps
  • The AtomicMultiSwapContract contract gracefully handles swap attempt failures and continues trying other compatible swaps

So in summary, the Batched Atomic Swap contract builds on the atomic swap contract to enable batching of multiple swaps in a single transaction.

Conclusion

The Batched Atomic Swap contract demonstrates how to batch multiple atomic swaps into a single transaction. By leveraging the atomic swap contract and multiparty authorizations, it's able to match compatible swaps and attempt them via the underlying atomic swap contract. Even if some swap attempts fail, it will continue trying other compatible swaps. The contract shows how authorized calls can be batched to increase efficiency, while still maintaining atomicity and authorization guarantees. Overall, the atomic multi-swap contract provides a useful building block for more complex exchange workflows on Soroban. Stay tuned for more post in this "Soroban Contracts 101" Series where we will dive deeper into Soroban Contracts and their functionalities.

Top comments (0)