liquidswap

172 阅读1分钟
public fun swap<X, Y, Curve>(
    x_in: Coin<X>,
    x_out: u64,
    y_in: Coin<Y>,
    y_out: u64
): (Coin<X>, Coin<Y>) acquires LiquidityPool, EventsStore {
    assert_no_emergency();
    
    assert!(coin_helper::is_sorted<X, Y>(), ERR_WRONG_PAIR_ORDERING);
    assert!(exists<LiquidityPool<X, Y, Curve>>(@liquidswap_pool_account), ERR_POOL_DOES_NOT_EXIST);

    assert_pool_unlocked<X, Y, Curve>();

    let x_in_val = coin::value(&x_in);
    let y_in_val = coin::value(&y_in);

    assert!(x_in_val > 0 || y_in_val > 0, ERR_EMPTY_COIN_IN);

    let pool = borrow_global_mut<LiquidityPool<X, Y, Curve>>(@liquidswap_pool_account);
    let x_reserve_size = coin::value(&pool.coin_x_reserve);
    let y_reserve_size = coin::value(&pool.coin_y_reserve);

    // Deposit new coins to liquidity pool.
    coin::merge(&mut pool.coin_x_reserve, x_in);
    coin::merge(&mut pool.coin_y_reserve, y_in);

    // Withdraw expected amount from reserves.
    let x_swapped = coin::extract(&mut pool.coin_x_reserve, x_out);
    let y_swapped = coin::extract(&mut pool.coin_y_reserve, y_out);

    // Confirm that lp_value for the pool hasn't been reduced.
    // For that, we compute lp_value with old reserves and lp_value with reserves after swap is done,
    // and make sure lp_value doesn't decrease
    let (x_res_new_after_fee, y_res_new_after_fee) =
        new_reserves_after_fees_scaled<Curve>(
            coin::value(&pool.coin_x_reserve),
            coin::value(&pool.coin_y_reserve),
            x_in_val,
            y_in_val,
            pool.fee
        );
    assert_lp_value_is_increased<Curve>(
        pool.x_scale,
        pool.y_scale,
        (x_reserve_size as u128),
        (y_reserve_size as u128),
        (x_res_new_after_fee as u128),
        (y_res_new_after_fee as u128),
    );

    split_fee_to_dao(pool, x_in_val, y_in_val);

    update_oracle<X, Y, Curve>(pool, x_reserve_size, y_reserve_size);

    let events_store = borrow_global_mut<EventsStore<X, Y, Curve>>(@liquidswap_pool_account);
    event::emit_event(
        &mut events_store.swap_handle,
        SwapEvent<X, Y, Curve> {
            x_in: x_in_val,
            y_in: y_in_val,
            x_out,
            y_out,
        });

    // Return swapped amount.
    (x_swapped, y_swapped)
}