mod test_util;
use bitcoin::Amount;
use chrono::{Local, TimeDelta};
use ddk::{
logger::{LogLevel, Logger},
Transport,
};
use ddk_manager::{contract::Contract, Storage};
use ddk_messages::Message;
use ddk_payouts::options::{Direction, OptionType};
use std::{
sync::Arc,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use test_util::{generate_blocks, test_ddk};
use tokio::time::sleep;
#[test_log::test(tokio::test)]
#[ignore]
async fn short_call() {
dotenv::dotenv().ok();
let logger_one = Arc::new(Logger::tracing("alice".to_string(), LogLevel::Info));
let logger_two = Arc::new(Logger::disabled("bob".to_string()));
let (alice, bob, oracle) = test_ddk(logger_one, logger_two).await;
let expiry = TimeDelta::seconds(15);
let timestamp: u32 = Local::now()
.checked_add_signed(expiry)
.unwrap()
.timestamp()
.try_into()
.unwrap();
let event_id = uuid::Uuid::new_v4().to_string();
let announcement = oracle
.oracle
.create_numeric_event(event_id, 20, false, 2, "BTC/USD".to_string(), timestamp)
.await
.unwrap();
let contract_input = ddk_payouts::options::build_option_order_offer(
&announcement,
Amount::ONE_BTC,
50_000,
Amount::from_sat(500_000),
1,
1_000,
OptionType::Call,
Direction::Short,
Amount::from_sat(100_500_000),
20,
)
.unwrap();
let offer = alice
.ddk
.manager
.send_offer_with_announcements(
&contract_input,
bob.ddk.transport.public_key(),
vec![vec![announcement.clone()]],
)
.await
.unwrap();
let contract_id = offer.temporary_contract_id.clone();
bob.ddk
.manager
.on_dlc_message(
&Message::Offer(offer),
alice.ddk.transport.public_key().clone(),
)
.await
.unwrap();
let accept = bob.ddk.manager.accept_contract_offer(&contract_id).await;
let (contract_id, _counterparty, accept_dlc) = accept.unwrap();
let alice_sign = alice
.ddk
.manager
.on_dlc_message(
&Message::Accept(accept_dlc),
bob.ddk.transport.public_key().clone(),
)
.await
.unwrap();
bob.ddk
.manager
.on_dlc_message(
&alice_sign.unwrap(),
alice.ddk.transport.public_key().clone(),
)
.await
.unwrap();
generate_blocks(10);
alice
.ddk
.manager
.periodic_check(false)
.await
.expect("alice check failed");
bob.ddk
.manager
.periodic_check(false)
.await
.expect("bob check failed");
let contract = bob.ddk.storage.get_contract(&contract_id).await.unwrap();
assert!(matches!(contract.unwrap(), Contract::Confirmed(_)));
bob.ddk.wallet.sync().await.unwrap();
alice.ddk.wallet.sync().await.unwrap();
let locktime = match alice.ddk.storage.get_contract(&contract_id).await.unwrap() {
Some(contract) => match contract {
Contract::Confirmed(signed_contract) => {
signed_contract.accepted_contract.dlc_transactions.cets[0]
.lock_time
.to_consensus_u32()
}
_ => unreachable!("No locktime."),
},
None => unreachable!("No locktime"),
};
let mut time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as u32;
let attestation = alice
.ddk
.oracle
.oracle
.sign_numeric_event(announcement.oracle_event.event_id.clone(), 53_000)
.await;
assert!(attestation.is_ok());
while time < announcement.clone().oracle_event.event_maturity_epoch || time < locktime {
let checked_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as u32;
time = checked_time;
generate_blocks(5);
}
bob.ddk.wallet.sync().await.unwrap();
alice.ddk.wallet.sync().await.unwrap();
bob.ddk
.manager
.close_confirmed_contract(&contract_id, vec![(0, attestation.unwrap())])
.await
.unwrap();
sleep(Duration::from_secs(10)).await;
let contract = bob
.ddk
.storage
.get_contract(&contract_id)
.await
.unwrap()
.unwrap();
assert!(matches!(contract, Contract::PreClosed(_)));
generate_blocks(10);
bob.ddk.manager.periodic_check(false).await.unwrap();
alice.ddk.manager.periodic_check(false).await.unwrap();
let contract = bob
.ddk
.storage
.get_contract(&contract_id)
.await
.unwrap()
.unwrap();
assert!(matches!(contract, Contract::Closed(_)));
let bob_contract = bob
.ddk
.storage
.get_contract(&contract_id)
.await
.unwrap()
.unwrap();
let alice_contract = alice
.ddk
.storage
.get_contract(&contract_id)
.await
.unwrap()
.unwrap();
match bob_contract {
Contract::Closed(c) => println!("Bob: {} sats", c.pnl),
_ => assert!(false),
}
match alice_contract {
Contract::Closed(c) => println!("Alice: {} sats", c.pnl),
_ => assert!(false),
}
}