Skip to content

Commit

Permalink
Locked amounts handling partially implemented.
Browse files Browse the repository at this point in the history
Active swaps V2 RPC WIP.
  • Loading branch information
Artem Vitae committed Dec 12, 2023
1 parent 38ed6ce commit a1563ba
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 34 deletions.
7 changes: 7 additions & 0 deletions mm2src/mm2_main/src/lp_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,11 @@ pub fn active_swaps(ctx: &MmArc) -> Result<Vec<Uuid>, String> {
uuids.push(*swap.uuid())
}
}

drop(swaps);

let swaps_v2 = swap_ctx.active_swaps_v2_infos.lock().unwrap();
uuids.extend(swaps_v2.keys());
Ok(uuids)
}

Expand Down Expand Up @@ -1549,6 +1554,8 @@ struct ActiveSwapsRes {
statuses: Option<HashMap<Uuid, SavedSwap>>,
}

/// This RPC does not support including statuses of v2 (Trading Protocol Upgrade) swaps.
/// It returns only uuids for these.
pub async fn active_swaps_rpc(ctx: MmArc, req: Json) -> Result<Response<Vec<u8>>, String> {
let req: ActiveSwapsReq = try_s!(json::from_value(req));
let uuids = try_s!(active_swaps(&ctx));
Expand Down
49 changes: 47 additions & 2 deletions mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,15 +655,60 @@ impl<MakerCoin: MmCoin + CoinAssocTypes, TakerCoin: MmCoin + SwapOpsV2> Storable
maker_coin_locked.retain(|locked| locked.swap_uuid != self.uuid);
};
},
_ => (),
MakerSwapEvent::WaitingForTakerFunding { .. }
| MakerSwapEvent::TakerFundingReceived { .. }
| MakerSwapEvent::MakerPaymentRefundRequired { .. }
| MakerSwapEvent::MakerPaymentRefunded { .. }
| MakerSwapEvent::TakerPaymentConfirmed { .. }
| MakerSwapEvent::TakerPaymentSpent { .. }
| MakerSwapEvent::Aborted { .. }
| MakerSwapEvent::Completed => (),
}
}

fn on_kickstart_event(
&mut self,
event: <<Self::Storage as StateMachineStorage>::DbRepr as StateMachineDbRepr>::Event,
) {
todo!()
match event {
MakerSwapEvent::Initialized {
maker_payment_trade_fee,
..
}
| MakerSwapEvent::WaitingForTakerFunding {
maker_payment_trade_fee,
..
}
| MakerSwapEvent::TakerFundingReceived {
maker_payment_trade_fee,
..
} => {
let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point");
let maker_coin_ticker: String = self.maker_coin.ticker().into();
let new_locked = LockedAmountInfo {
swap_uuid: self.uuid,
locked_amount: LockedAmount {
coin: maker_coin_ticker.clone(),
amount: self.maker_volume.clone(),
trade_fee: Some(maker_payment_trade_fee.clone().into()),
},
};
swaps_ctx
.locked_amounts
.lock()
.unwrap()
.entry(maker_coin_ticker)
.or_insert_with(Vec::new)
.push(new_locked);
},
MakerSwapEvent::MakerPaymentSentFundingSpendGenerated { .. }
| MakerSwapEvent::MakerPaymentRefundRequired { .. }
| MakerSwapEvent::MakerPaymentRefunded { .. }
| MakerSwapEvent::TakerPaymentConfirmed { .. }
| MakerSwapEvent::TakerPaymentSpent { .. }
| MakerSwapEvent::Aborted { .. }
| MakerSwapEvent::Completed => (),
}
}
}

Expand Down
34 changes: 34 additions & 0 deletions mm2src/mm2_main/src/lp_swap/swap_v2_rpcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use mm2_core::mm_ctx::MmArc;
use mm2_err_handle::prelude::*;
use mm2_number::{MmNumber, MmNumberMultiRepr};
use serde::de::DeserializeOwned;
use std::collections::HashMap;
use std::num::NonZeroUsize;
use uuid::Uuid;

Expand Down Expand Up @@ -438,3 +439,36 @@ pub(crate) async fn my_recent_swaps_rpc(
found_records: db_result.uuids_and_types.len(),
})
}

#[derive(Deserialize)]
pub(crate) struct ActiveSwapsRequest {
#[serde(default)]
include_status: bool,
}

#[derive(Display, Serialize, SerializeErrorType)]
#[serde(tag = "error_type", content = "error_data")]
pub(crate) enum ActiveSwapsErr {
Internal(String),
}

impl HttpStatusCode for ActiveSwapsErr {
fn status_code(&self) -> StatusCode {
match self {
ActiveSwapsErr::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}

#[derive(Serialize)]
pub(crate) struct ActiveSwapsResponse {
uuids: Vec<Uuid>,
statuses: HashMap<Uuid, SwapRpcData>,
}

pub(crate) async fn active_swaps_rpc(
_ctx: MmArc,
_req: ActiveSwapsRequest,
) -> MmResult<ActiveSwapsResponse, ActiveSwapsErr> {
unimplemented!()
}
47 changes: 46 additions & 1 deletion mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ pub enum TakerSwapEvent {
maker_coin_start_block: u64,
taker_coin_start_block: u64,
negotiation_data: StoredNegotiationData,
taker_payment_fee: SavedTradeFee,
maker_payment_spend_fee: SavedTradeFee,
},
/// Sent taker funding tx.
TakerFundingSent {
Expand Down Expand Up @@ -478,6 +480,8 @@ impl<MakerCoin: MmCoin + CoinAssocTypes, TakerCoin: MmCoin + SwapOpsV2> Storable
maker_coin_start_block,
taker_coin_start_block,
negotiation_data,
taker_payment_fee,
maker_payment_spend_fee,
} => Box::new(Negotiated {
maker_coin_start_block,
taker_coin_start_block,
Expand All @@ -486,6 +490,8 @@ impl<MakerCoin: MmCoin + CoinAssocTypes, TakerCoin: MmCoin + SwapOpsV2> Storable
&recreate_ctx.maker_coin,
&recreate_ctx.taker_coin,
)?,
taker_payment_fee,
maker_payment_spend_fee,
}),
TakerSwapEvent::TakerFundingSent {
maker_coin_start_block,
Expand Down Expand Up @@ -765,7 +771,40 @@ impl<MakerCoin: MmCoin + CoinAssocTypes, TakerCoin: MmCoin + SwapOpsV2> Storable
&mut self,
event: <<Self::Storage as StateMachineStorage>::DbRepr as StateMachineDbRepr>::Event,
) {
todo!()
match event {
TakerSwapEvent::Initialized { taker_payment_fee, .. }
| TakerSwapEvent::Negotiated { taker_payment_fee, .. } => {
let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point");
let taker_coin_ticker: String = self.taker_coin.ticker().into();
let new_locked = LockedAmountInfo {
swap_uuid: self.uuid,
locked_amount: LockedAmount {
coin: taker_coin_ticker.clone(),
amount: &(&self.taker_volume + &self.dex_fee) + &self.taker_premium,
trade_fee: Some(taker_payment_fee.into()),
},
};
swaps_ctx
.locked_amounts
.lock()
.unwrap()
.entry(taker_coin_ticker)
.or_insert_with(Vec::new)
.push(new_locked);
},
TakerSwapEvent::TakerFundingSent { .. }
| TakerSwapEvent::TakerFundingRefundRequired { .. }
| TakerSwapEvent::MakerPaymentAndFundingSpendPreimgReceived { .. }
| TakerSwapEvent::TakerPaymentSent { .. }
| TakerSwapEvent::TakerPaymentRefundRequired { .. }
| TakerSwapEvent::MakerPaymentConfirmed { .. }
| TakerSwapEvent::TakerPaymentSpent { .. }
| TakerSwapEvent::MakerPaymentSpent { .. }
| TakerSwapEvent::TakerFundingRefunded { .. }
| TakerSwapEvent::TakerPaymentRefunded { .. }
| TakerSwapEvent::Aborted { .. }
| TakerSwapEvent::Completed => (),
}
}
}

Expand Down Expand Up @@ -1020,6 +1059,8 @@ impl<MakerCoin: MmCoin + CoinAssocTypes, TakerCoin: MmCoin + SwapOpsV2> State fo
maker_coin_swap_contract: maker_negotiation.maker_coin_swap_contract,
taker_coin_swap_contract: maker_negotiation.taker_coin_swap_contract,
},
taker_payment_fee: self.taker_payment_fee,
maker_payment_spend_fee: self.maker_payment_spend_fee,
};
Self::change_state(next_state, state_machine).await
}
Expand Down Expand Up @@ -1070,6 +1111,8 @@ struct Negotiated<MakerCoin: CoinAssocTypes, TakerCoin: CoinAssocTypes> {
maker_coin_start_block: u64,
taker_coin_start_block: u64,
negotiation_data: NegotiationData<MakerCoin, TakerCoin>,
taker_payment_fee: SavedTradeFee,
maker_payment_spend_fee: SavedTradeFee,
}

impl<MakerCoin: CoinAssocTypes, TakerCoin: SwapOpsV2> TransitionFrom<Initialized<MakerCoin, TakerCoin>>
Expand Down Expand Up @@ -1127,6 +1170,8 @@ impl<MakerCoin: MmCoin + CoinAssocTypes, TakerCoin: MmCoin + SwapOpsV2> Storable
maker_coin_start_block: self.maker_coin_start_block,
taker_coin_start_block: self.taker_coin_start_block,
negotiation_data: self.negotiation_data.to_stored_data(),
taker_payment_fee: self.taker_payment_fee.clone(),
maker_payment_spend_fee: self.maker_payment_spend_fee.clone(),
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::mm2::lp_native_dex::init_hw::{cancel_init_trezor, init_trezor, init_t
use crate::mm2::lp_native_dex::init_metamask::{cancel_connect_metamask, connect_metamask, connect_metamask_status};
use crate::mm2::lp_ordermatch::{best_orders_rpc_v2, orderbook_rpc_v2, start_simple_market_maker_bot,
stop_simple_market_maker_bot};
use crate::mm2::lp_swap::swap_v2_rpcs::{my_recent_swaps_rpc, my_swap_status_rpc};
use crate::mm2::lp_swap::swap_v2_rpcs::{active_swaps_rpc, my_recent_swaps_rpc, my_swap_status_rpc};
use crate::mm2::rpc::rate_limiter::{process_rate_limit, RateLimitContext};
use crate::{mm2::lp_stats::{add_node_to_version_stat, remove_node_from_version_stat, start_version_stat_collection,
stop_version_stat_collection, update_version_stat_collection},
Expand Down Expand Up @@ -154,6 +154,7 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult<Re

match request.method.as_str() {
"account_balance" => handle_mmrpc(ctx, request, account_balance).await,
"active_swaps" => handle_mmrpc(ctx, request, active_swaps_rpc).await,
"add_delegation" => handle_mmrpc(ctx, request, add_delegation).await,
"add_node_to_version_stat" => handle_mmrpc(ctx, request, add_node_to_version_stat).await,
"best_orders" => handle_mmrpc(ctx, request, best_orders_rpc_v2).await,
Expand Down
45 changes: 37 additions & 8 deletions mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use coins::{GenTakerFundingSpendArgs, RefundFundingSecretArgs, RefundPaymentArgs
Transaction, ValidateTakerFundingArgs};
use common::{block_on, now_sec};
use mm2_number::MmNumber;
use mm2_test_helpers::for_tests::{check_recent_swaps, coins_needed_for_kickstart, disable_coin, disable_coin_err,
enable_native, get_locked_amount, mm_dump, my_swap_status, mycoin1_conf,
mycoin_conf, start_swaps, wait_for_swap_finished, wait_for_swap_status,
MarketMakerIt, Mm2TestConf};
use mm2_test_helpers::for_tests::{active_swaps, check_recent_swaps, coins_needed_for_kickstart, disable_coin,
disable_coin_err, enable_native, get_locked_amount, mm_dump, my_swap_status,
mycoin1_conf, mycoin_conf, start_swaps, wait_for_swap_finished,
wait_for_swap_status, MarketMakerIt, Mm2TestConf};
use mm2_test_helpers::structs::MmNumberMultiRepr;
use script::{Builder, Opcode};
use serialization::serialize;
Expand Down Expand Up @@ -230,6 +230,13 @@ fn test_v2_swap_utxo_utxo() {
println!("{:?}", uuids);

let parsed_uuids: Vec<Uuid> = uuids.iter().map(|u| u.parse().unwrap()).collect();

let active_swaps_bob = block_on(active_swaps(&mm_bob));
assert_eq!(active_swaps_bob.uuids, parsed_uuids);

let active_swaps_alice = block_on(active_swaps(&mm_alice));
assert_eq!(active_swaps_alice.uuids, parsed_uuids);

// disabling coins used in active swaps must not work
let err = block_on(disable_coin_err(&mm_bob, MYCOIN, false));
assert_eq!(err.active_swaps, parsed_uuids);
Expand Down Expand Up @@ -319,10 +326,12 @@ fn test_v2_swap_utxo_utxo_kickstart() {
&[(MYCOIN, MYCOIN1)],
1.0,
1.0,
100.,
777.,
));
println!("{:?}", uuids);

let parsed_uuids: Vec<Uuid> = uuids.iter().map(|u| u.parse().unwrap()).collect();

for uuid in uuids.iter() {
let maker_swap_status = block_on(my_swap_status(&mm_bob, uuid));
println!("Maker swap {} status before stop {:?}", uuid, maker_swap_status);
Expand All @@ -337,15 +346,15 @@ fn test_v2_swap_utxo_utxo_kickstart() {
bob_conf.conf["dbdir"] = mm_bob.folder.join("DB").to_str().unwrap().into();
bob_conf.conf["log"] = mm_bob.folder.join("mm2_dup.log").to_str().unwrap().into();

let mm_bob = MarketMakerIt::start(bob_conf.conf, bob_conf.rpc_password, None).unwrap();
let mut mm_bob = MarketMakerIt::start(bob_conf.conf, bob_conf.rpc_password, None).unwrap();
let (_bob_dump_log, _bob_dump_dashboard) = mm_dump(&mm_bob.log_path);
log!("Bob log path: {}", mm_bob.log_path.display());

alice_conf.conf["dbdir"] = mm_alice.folder.join("DB").to_str().unwrap().into();
alice_conf.conf["log"] = mm_alice.folder.join("mm2_dup.log").to_str().unwrap().into();
alice_conf.conf["seednodes"] = vec![mm_bob.ip.to_string()].into();

let mm_alice = MarketMakerIt::start(alice_conf.conf, alice_conf.rpc_password, None).unwrap();
let mut mm_alice = MarketMakerIt::start(alice_conf.conf, alice_conf.rpc_password, None).unwrap();
let (_alice_dump_log, _alice_dump_dashboard) = mm_dump(&mm_alice.log_path);
log!("Alice log path: {}", mm_alice.log_path.display());

Expand All @@ -365,17 +374,37 @@ fn test_v2_swap_utxo_utxo_kickstart() {
// give swaps 1 second to restart
std::thread::sleep(Duration::from_secs(1));

let active_swaps_bob = block_on(active_swaps(&mm_bob));
assert_eq!(active_swaps_bob.uuids, parsed_uuids);

let active_swaps_alice = block_on(active_swaps(&mm_alice));
assert_eq!(active_swaps_alice.uuids, parsed_uuids);

// coins must be virtually locked after kickstart until swap transactions are sent
let locked_alice = block_on(get_locked_amount(&mm_alice, MYCOIN1));
assert_eq!(locked_alice.coin, MYCOIN1);
let expected: MmNumberMultiRepr = MmNumber::from("778.00001").into();
assert_eq!(locked_alice.locked_amount, expected);

let locked_bob = block_on(get_locked_amount(&mm_bob, MYCOIN));
assert_eq!(locked_bob.coin, MYCOIN);
let expected: MmNumberMultiRepr = MmNumber::from("777.00001").into();
assert_eq!(locked_bob.locked_amount, expected);

// amount must unlocked after funding tx is sent
block_on(mm_alice.wait_for_log(20., |log| log.contains("Sent taker funding"))).unwrap();
let locked_alice = block_on(get_locked_amount(&mm_alice, MYCOIN1));
assert_eq!(locked_alice.coin, MYCOIN1);
let expected: MmNumberMultiRepr = MmNumber::from("778.00001").into();
let expected: MmNumberMultiRepr = MmNumber::from("0").into();
assert_eq!(locked_alice.locked_amount, expected);

// amount must unlocked after maker payment is sent
block_on(mm_bob.wait_for_log(20., |log| log.contains("Sent maker payment"))).unwrap();
let locked_bob = block_on(get_locked_amount(&mm_bob, MYCOIN));
assert_eq!(locked_bob.coin, MYCOIN);
let expected: MmNumberMultiRepr = MmNumber::from("0").into();
assert_eq!(locked_bob.locked_amount, expected);

for uuid in uuids {
block_on(wait_for_swap_finished(&mm_bob, &uuid, 60));
block_on(wait_for_swap_finished(&mm_alice, &uuid, 30));
Expand Down
22 changes: 0 additions & 22 deletions mm2src/mm2_state_machine/src/storable_state_machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,28 +116,6 @@ impl<T: StorableState + State<StateMachine = Self::StateMachine> + Send> Restore
fn into_state(self: Box<Self>) -> Box<dyn State<StateMachine = Self::StateMachine>> { self }
}

trait Trait1 {
fn method1(&self);
}

trait Trait2: Trait1 {
fn method2(&self);
}

struct MyStruct;

impl Trait1 for MyStruct {
fn method1(&self) {
println!("Calling method1");
}
}

impl Trait2 for MyStruct {
fn method2(&self) {
println!("Calling method2");
}
}

/// A struct representing a restored state machine.
pub struct RestoredMachine<M: StorableStateMachine> {
machine: M,
Expand Down
11 changes: 11 additions & 0 deletions mm2src/mm2_test_helpers/src/for_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3178,3 +3178,14 @@ fn test_parse_env_file() {
)
);
}

pub async fn active_swaps(mm: &MarketMakerIt) -> ActiveSwapsResponse {
let request = json!({
"userpass": mm.userpass,
"method": "active_swaps",
"params": []
});
let response = mm.rpc(&request).await.unwrap();
assert_eq!(response.0, StatusCode::OK, "'active_swaps' failed: {}", response.1);
json::from_str(&response.1).unwrap()
}
7 changes: 7 additions & 0 deletions mm2src/mm2_test_helpers/src/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1067,3 +1067,10 @@ pub struct DisableCoinOrders {
pub struct CoinsNeededForKickstartResponse {
pub result: Vec<String>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct ActiveSwapsResponse {
pub uuids: Vec<Uuid>,
pub statuses: Option<HashMap<Uuid, Json>>,
}

0 comments on commit a1563ba

Please sign in to comment.