module example::atomic_swap {
use iota::object::{Self, UID, ID};
use iota::coin::Coin;
public struct Swap<phantom T, phantom U> has key {
id: UID,
offered: Coin<T>,
expected_amount: u64,
}
/// Hot potato to ensure swap completion
public struct SwapTicket<phantom T, phantom U> {
swap_id: ID,
offered: Coin<T>,
}
/// Create swap offer
public fun create_swap<T, U>(
offered: Coin<T>,
expected_amount: u64,
ctx: &mut TxContext
): Swap<T, U> {
Swap {
id: object::new(ctx),
offered,
expected_amount,
}
}
/// Accept swap (returns hot potato)
public fun accept_swap<T, U>(
swap: Swap<T, U>,
payment: Coin<U>,
): SwapTicket<T, U> {
let Swap { id, offered, expected_amount } = swap;
assert!(payment.value() >= expected_amount, 0);
// Payment is accepted
transfer::public_transfer(payment, @counterparty);
let swap_id = id.to_inner();
id.delete();
// Return hot potato with the offered coins
SwapTicket {
swap_id,
offered,
}
}
/// Complete swap (consume hot potato)
public fun complete_swap<T, U>(
ticket: SwapTicket<T, U>,
recipient: address,
) {
let SwapTicket { swap_id: _, offered } = ticket;
transfer::public_transfer(offered, recipient);
}
}