Skip to content

Atomic Swap

Soroban Atomic Swap
#![no_std]
use soroban_sdk::{contract, contractimpl, token, Address, Env, IntoVal, log};
 
#[contract]
pub struct AtomicSwap;
 
#[contractimpl]
impl AtomicSwap {
    pub fn swap (
        env: Env,
        a: Address,
        b: Address,
        token_a: Address,
        token_b: Address,
        amount_a: i128,
        min_b_for_a: i128,
        amount_b: i128,
        min_a_for_b: i128,
    ) {
 
        /// @dev should remove logs before deploying smart contracts
        log!(&env, "Amount A: {}, Amount B: {}", amount_a, amount_b);
        log!(&env, "Minimum B amount for A: {}, Minimum A amount for B: {}", min_b_for_a, min_a_for_b);
 
        if amount_b < min_b_for_a {
            panic!("not enough token B for token A");
        }
 
        if amount_a < min_a_for_b {
            panic!("not enough token A for token B");
        }
 
        a.require_auth_for_args(
            (token_a.clone(), token_b.clone(), amount_a, min_b_for_a).into_val(&env),
        );
 
        b.require_auth_for_args(
            (token_b.clone(), token_a.clone(), amount_b, min_a_for_b).into_val(&env),
        );
 
        move_token(&env, &token_a, &a, &b, amount_a, min_a_for_b);
        move_token(&env, &token_b, &b, &a, amount_b, min_b_for_a);
    }
}
 
fn move_token (
    env: &Env,
    token: &Address,
    from: &Address,
    to: &Address,
    max_spend_amount: i128,
    transfer_amount: i128,
) {
    let token = token::Client::new(env, token);
    let contract_address = env.current_contract_address();
 
    token.transfer(from, &contract_address, &max_spend_amount);
 
    token.transfer(&contract_address, to, &transfer_amount);
 
    token.transfer(
        &contract_address,
        from,
        &(max_spend_amount - transfer_amount),
    );
}

Explanation

#![no_std] This attribute prevents linking to the standard library, making the code lighter and more efficient for Soroban contracts. It's big so we save on size.

use soroban_sdk::{contract, contractimpl, Env, log} Imports stuffs from the Soroban SDK. Env is basic Soroban type, we need it because we can't use the Rust standard library.

#[contract] Marks the struct as a Soroban smart contract. Soroban smart contracts are defined as Rust structs.

#[contractimpl] Marks the implementation block as containing contract methods and transforms it to code that Soroban can evaluate directly.

swap This function takes in the following parameters:

  • env: The current environment, providing access to contract state and functionality.
  • a and b: The addresses of the two parties involved in the swap.
  • token_a and token_b: The addresses of the tokens being exchanged.
  • amount_a and amount_b: The amounts of each token to be exchanged.
  • min_b_for_a and min_a_for_b: Minimum acceptable amounts of the other token that each party is willing to receive.

if amount_b < min_b_for_a { ... } This checks if the amount of token B being offered is less than the minimum acceptable amount for token A. If so, panics with an error message.

if amount_a < min_a_for_b { ... } This performs a similar check as above, but for token A.

require_auth_for_args(...) Ensures that the parties a and b have authorized the transaction by providing the correct arguments.

move_token This function transfers the tokens through the contract's address to ensure that both parties receive their respective tokens simultaneously.

Run in Playground

Loading playground...