|
|
@ -8,12 +8,14 @@ use bdk::SignOptions; |
|
|
|
use bitcoin::util::psbt::PartiallySignedTransaction; |
|
|
|
use cfd_protocol::{ |
|
|
|
close_transaction, commit_descriptor, compute_adaptor_pk, create_cfd_transactions, |
|
|
|
finalize_spend_transaction, interval, lock_descriptor, punish_transaction, |
|
|
|
renew_cfd_transactions, spending_tx_sighash, CfdTransactions, Payout, PunishParams, |
|
|
|
TransactionExt, WalletExt, |
|
|
|
finalize_spend_transaction, generate_payouts, interval, lock_descriptor, punish_transaction, |
|
|
|
renew_cfd_transactions, spending_tx_sighash, Announcement, Cets, CfdTransactions, Payout, |
|
|
|
PunishParams, TransactionExt, WalletExt, |
|
|
|
}; |
|
|
|
use rand::{thread_rng, CryptoRng, RngCore}; |
|
|
|
use secp256k1_zkp::{schnorrsig, EcdsaAdaptorSignature, SecretKey, Signature, SECP256K1}; |
|
|
|
use std::collections::HashMap; |
|
|
|
use std::iter::FromIterator; |
|
|
|
use std::str::FromStr; |
|
|
|
|
|
|
|
#[test] |
|
|
@ -26,25 +28,38 @@ fn create_cfd() { |
|
|
|
let maker_wallet = build_wallet(&mut rng, Amount::from_btc(0.4).unwrap(), 5).unwrap(); |
|
|
|
let taker_wallet = build_wallet(&mut rng, Amount::from_btc(0.4).unwrap(), 5).unwrap(); |
|
|
|
|
|
|
|
let oracle_data = OliviaData::example(); |
|
|
|
let oracle_pk = oracle_data.pk; |
|
|
|
let nonce_pks = oracle_data.nonce_pks.clone(); |
|
|
|
let oracle_data_0 = OliviaData::example_0(); |
|
|
|
let oracle_data_1 = OliviaData::example_1(); |
|
|
|
|
|
|
|
let payouts = vec![ |
|
|
|
Payout::new( |
|
|
|
0..=40_000, |
|
|
|
Amount::from_btc(1.5).unwrap(), |
|
|
|
let oracle_pk = oracle_data_0.pk; |
|
|
|
|
|
|
|
let event_0 = oracle_data_0.announcement(); |
|
|
|
let event_1 = oracle_data_1.announcement(); |
|
|
|
|
|
|
|
let payouts_per_event = HashMap::from_iter([ |
|
|
|
( |
|
|
|
event_0.clone(), |
|
|
|
generate_payouts(0..=50_000, Amount::ZERO, Amount::from_btc(2.0).unwrap()).unwrap(), |
|
|
|
), |
|
|
|
( |
|
|
|
event_1.clone(), |
|
|
|
[ |
|
|
|
generate_payouts( |
|
|
|
40_001..=70_000, |
|
|
|
Amount::from_btc(0.5).unwrap(), |
|
|
|
Amount::from_btc(1.5).unwrap(), |
|
|
|
) |
|
|
|
.unwrap(), |
|
|
|
Payout::new( |
|
|
|
40_001..=70_000, |
|
|
|
Amount::ZERO, |
|
|
|
Amount::from_btc(2.0).unwrap(), |
|
|
|
generate_payouts( |
|
|
|
70_001..=100_000, |
|
|
|
Amount::from_btc(1.5).unwrap(), |
|
|
|
Amount::from_btc(0.5).unwrap(), |
|
|
|
) |
|
|
|
.unwrap(), |
|
|
|
] |
|
|
|
.concat(); |
|
|
|
.concat(), |
|
|
|
), |
|
|
|
]); |
|
|
|
|
|
|
|
let cet_timelock = 0; |
|
|
|
let refund_timelock = 0; |
|
|
@ -53,11 +68,16 @@ fn create_cfd() { |
|
|
|
&mut rng, |
|
|
|
(&maker_wallet, maker_lock_amount), |
|
|
|
(&taker_wallet, taker_lock_amount), |
|
|
|
(oracle_pk, &nonce_pks), |
|
|
|
payouts, |
|
|
|
oracle_pk, |
|
|
|
payouts_per_event, |
|
|
|
(cet_timelock, refund_timelock), |
|
|
|
); |
|
|
|
|
|
|
|
assert_contains_cets_for_event(&maker_cfd_txs.cets, &event_0); |
|
|
|
assert_contains_cets_for_event(&maker_cfd_txs.cets, &event_1); |
|
|
|
assert_contains_cets_for_event(&taker_cfd_txs.cets, &event_0); |
|
|
|
assert_contains_cets_for_event(&taker_cfd_txs.cets, &event_1); |
|
|
|
|
|
|
|
let lock_desc = lock_descriptor(maker.pk, taker.pk); |
|
|
|
let lock_amount = maker_lock_amount + taker_lock_amount; |
|
|
|
|
|
|
@ -70,7 +90,7 @@ fn create_cfd() { |
|
|
|
verify_cfd_sigs( |
|
|
|
(&maker_cfd_txs, maker.pk, maker.pub_pk), |
|
|
|
(&taker_cfd_txs, taker.pk, taker.pub_pk), |
|
|
|
(oracle_pk, &nonce_pks), |
|
|
|
(oracle_pk, vec![event_0, event_1]), |
|
|
|
(&lock_desc, lock_amount), |
|
|
|
(&commit_desc, commit_amount), |
|
|
|
); |
|
|
@ -96,7 +116,7 @@ fn create_cfd() { |
|
|
|
taker.rev_sk, |
|
|
|
taker_addr, |
|
|
|
), |
|
|
|
oracle_data, |
|
|
|
&[oracle_data_0, oracle_data_1], |
|
|
|
(lock_desc, lock_amount), |
|
|
|
(commit_desc, commit_amount), |
|
|
|
); |
|
|
@ -112,20 +132,23 @@ fn renew_cfd() { |
|
|
|
let maker_wallet = build_wallet(&mut rng, Amount::from_btc(0.4).unwrap(), 5).unwrap(); |
|
|
|
let taker_wallet = build_wallet(&mut rng, Amount::from_btc(0.4).unwrap(), 5).unwrap(); |
|
|
|
|
|
|
|
let oracle_data = OliviaData::example(); |
|
|
|
let oracle_data = OliviaData::example_0(); |
|
|
|
let oracle_pk = oracle_data.pk; |
|
|
|
let nonce_pks = oracle_data.nonce_pks.clone(); |
|
|
|
let event = oracle_data.announcement(); |
|
|
|
|
|
|
|
let payouts = vec![ |
|
|
|
Payout::new(0..=10_000, Amount::from_btc(2.0).unwrap(), Amount::ZERO).unwrap(), |
|
|
|
Payout::new( |
|
|
|
let payouts_per_event = HashMap::from_iter([( |
|
|
|
event, |
|
|
|
vec![ |
|
|
|
generate_payouts(0..=10_000, Amount::from_btc(2.0).unwrap(), Amount::ZERO).unwrap(), |
|
|
|
generate_payouts( |
|
|
|
10_001..=50_000, |
|
|
|
Amount::ZERO, |
|
|
|
Amount::from_btc(2.0).unwrap(), |
|
|
|
) |
|
|
|
.unwrap(), |
|
|
|
] |
|
|
|
.concat(); |
|
|
|
.concat(), |
|
|
|
)]); |
|
|
|
|
|
|
|
let cet_timelock = 0; |
|
|
|
let refund_timelock = 0; |
|
|
@ -134,8 +157,8 @@ fn renew_cfd() { |
|
|
|
&mut rng, |
|
|
|
(&maker_wallet, maker_lock_amount), |
|
|
|
(&taker_wallet, taker_lock_amount), |
|
|
|
(oracle_pk, &nonce_pks), |
|
|
|
payouts, |
|
|
|
oracle_pk, |
|
|
|
payouts_per_event, |
|
|
|
(cet_timelock, refund_timelock), |
|
|
|
); |
|
|
|
|
|
|
@ -147,21 +170,28 @@ fn renew_cfd() { |
|
|
|
let (taker_rev_sk, taker_rev_pk) = make_keypair(&mut rng); |
|
|
|
let (taker_pub_sk, taker_pub_pk) = make_keypair(&mut rng); |
|
|
|
|
|
|
|
let payouts = vec![ |
|
|
|
Payout::new( |
|
|
|
let oracle_data = OliviaData::example_1(); |
|
|
|
let oracle_pk = oracle_data.pk; |
|
|
|
let event = oracle_data.announcement(); |
|
|
|
|
|
|
|
let payouts_per_event = HashMap::from_iter([( |
|
|
|
event.clone(), |
|
|
|
vec![ |
|
|
|
generate_payouts( |
|
|
|
0..=50_000, |
|
|
|
Amount::from_btc(1.5).unwrap(), |
|
|
|
Amount::from_btc(0.5).unwrap(), |
|
|
|
) |
|
|
|
.unwrap(), |
|
|
|
Payout::new( |
|
|
|
generate_payouts( |
|
|
|
50_001..=70_000, |
|
|
|
Amount::from_btc(0.5).unwrap(), |
|
|
|
Amount::from_btc(1.5).unwrap(), |
|
|
|
) |
|
|
|
.unwrap(), |
|
|
|
] |
|
|
|
.concat(); |
|
|
|
.concat(), |
|
|
|
)]); |
|
|
|
|
|
|
|
let maker_cfd_txs = renew_cfd_transactions( |
|
|
|
maker_cfd_txs.lock, |
|
|
@ -183,9 +213,9 @@ fn renew_cfd() { |
|
|
|
publish_pk: taker_pub_pk, |
|
|
|
}, |
|
|
|
), |
|
|
|
(oracle_pk, &nonce_pks), |
|
|
|
oracle_pk, |
|
|
|
(cet_timelock, refund_timelock), |
|
|
|
payouts.clone(), |
|
|
|
payouts_per_event.clone(), |
|
|
|
maker.sk, |
|
|
|
) |
|
|
|
.unwrap(); |
|
|
@ -210,13 +240,16 @@ fn renew_cfd() { |
|
|
|
publish_pk: taker_pub_pk, |
|
|
|
}, |
|
|
|
), |
|
|
|
(oracle_pk, &nonce_pks), |
|
|
|
oracle_pk, |
|
|
|
(cet_timelock, refund_timelock), |
|
|
|
payouts, |
|
|
|
payouts_per_event, |
|
|
|
taker.sk, |
|
|
|
) |
|
|
|
.unwrap(); |
|
|
|
|
|
|
|
assert_contains_cets_for_event(&maker_cfd_txs.cets, &event); |
|
|
|
assert_contains_cets_for_event(&taker_cfd_txs.cets, &event); |
|
|
|
|
|
|
|
let lock_desc = lock_descriptor(maker.pk, taker.pk); |
|
|
|
let lock_amount = maker_lock_amount + taker_lock_amount; |
|
|
|
|
|
|
@ -229,7 +262,7 @@ fn renew_cfd() { |
|
|
|
verify_cfd_sigs( |
|
|
|
(&maker_cfd_txs, maker.pk, maker_pub_pk), |
|
|
|
(&taker_cfd_txs, taker.pk, taker_pub_pk), |
|
|
|
(oracle_pk, &nonce_pks), |
|
|
|
(oracle_pk, vec![event]), |
|
|
|
(&lock_desc, lock_amount), |
|
|
|
(&commit_desc, commit_amount), |
|
|
|
); |
|
|
@ -255,7 +288,7 @@ fn renew_cfd() { |
|
|
|
taker_rev_sk, |
|
|
|
taker_addr, |
|
|
|
), |
|
|
|
oracle_data, |
|
|
|
&[oracle_data], |
|
|
|
(lock_desc, lock_amount), |
|
|
|
(commit_desc, commit_amount), |
|
|
|
) |
|
|
@ -271,17 +304,19 @@ fn collaboratively_close_cfd() { |
|
|
|
let maker_wallet = build_wallet(&mut rng, Amount::from_btc(0.4).unwrap(), 5).unwrap(); |
|
|
|
let taker_wallet = build_wallet(&mut rng, Amount::from_btc(0.4).unwrap(), 5).unwrap(); |
|
|
|
|
|
|
|
let oracle_data = OliviaData::example(); |
|
|
|
let oracle_data = OliviaData::example_0(); |
|
|
|
let oracle_pk = oracle_data.pk; |
|
|
|
let nonce_pks = oracle_data.nonce_pks; |
|
|
|
let event = oracle_data.announcement(); |
|
|
|
|
|
|
|
let payouts = vec![Payout::new( |
|
|
|
let payouts_per_event = HashMap::from_iter([( |
|
|
|
event, |
|
|
|
generate_payouts( |
|
|
|
0..=100_000, |
|
|
|
Amount::from_btc(1.5).unwrap(), |
|
|
|
Amount::from_btc(0.5).unwrap(), |
|
|
|
) |
|
|
|
.unwrap()] |
|
|
|
.concat(); |
|
|
|
.unwrap(), |
|
|
|
)]); |
|
|
|
|
|
|
|
let cet_timelock = 0; |
|
|
|
let refund_timelock = 0; |
|
|
@ -290,8 +325,8 @@ fn collaboratively_close_cfd() { |
|
|
|
&mut rng, |
|
|
|
(&maker_wallet, maker_lock_amount), |
|
|
|
(&taker_wallet, taker_lock_amount), |
|
|
|
(oracle_pk, &nonce_pks), |
|
|
|
payouts, |
|
|
|
oracle_pk, |
|
|
|
payouts_per_event, |
|
|
|
(cet_timelock, refund_timelock), |
|
|
|
); |
|
|
|
|
|
|
@ -335,8 +370,8 @@ fn create_cfd_txs( |
|
|
|
rng: &mut (impl RngCore + CryptoRng), |
|
|
|
(maker_wallet, maker_lock_amount): (&bdk::Wallet<(), bdk::database::MemoryDatabase>, Amount), |
|
|
|
(taker_wallet, taker_lock_amount): (&bdk::Wallet<(), bdk::database::MemoryDatabase>, Amount), |
|
|
|
(oracle_pk, nonce_pks): (schnorrsig::PublicKey, &[schnorrsig::PublicKey]), |
|
|
|
payouts: Vec<Payout>, |
|
|
|
oracle_pk: schnorrsig::PublicKey, |
|
|
|
payouts_per_event: HashMap<Announcement, Vec<Payout>>, |
|
|
|
(cet_timelock, refund_timelock): (u32, u32), |
|
|
|
) -> ( |
|
|
|
CfdTransactions, |
|
|
@ -362,6 +397,7 @@ fn create_cfd_txs( |
|
|
|
let taker_params = taker_wallet |
|
|
|
.build_party_params(taker_lock_amount, taker_pk) |
|
|
|
.unwrap(); |
|
|
|
|
|
|
|
let maker_cfd_txs = create_cfd_transactions( |
|
|
|
( |
|
|
|
maker_params.clone(), |
|
|
@ -377,9 +413,9 @@ fn create_cfd_txs( |
|
|
|
publish_pk: taker_pub_pk, |
|
|
|
}, |
|
|
|
), |
|
|
|
(oracle_pk, nonce_pks), |
|
|
|
oracle_pk, |
|
|
|
(cet_timelock, refund_timelock), |
|
|
|
payouts.clone(), |
|
|
|
payouts_per_event.clone(), |
|
|
|
maker_sk, |
|
|
|
) |
|
|
|
.unwrap(); |
|
|
@ -398,9 +434,9 @@ fn create_cfd_txs( |
|
|
|
publish_pk: taker_pub_pk, |
|
|
|
}, |
|
|
|
), |
|
|
|
(oracle_pk, nonce_pks), |
|
|
|
oracle_pk, |
|
|
|
(cet_timelock, refund_timelock), |
|
|
|
payouts, |
|
|
|
payouts_per_event, |
|
|
|
taker_sk, |
|
|
|
) |
|
|
|
.unwrap(); |
|
|
@ -440,7 +476,7 @@ struct CfdKeys { |
|
|
|
fn verify_cfd_sigs( |
|
|
|
(maker_cfd_txs, maker_pk, maker_publish_pk): (&CfdTransactions, PublicKey, PublicKey), |
|
|
|
(taker_cfd_txs, taker_pk, taker_publish_pk): (&CfdTransactions, PublicKey, PublicKey), |
|
|
|
(oracle_pk, nonce_pks): (schnorrsig::PublicKey, &[schnorrsig::PublicKey]), |
|
|
|
(oracle_pk, events): (schnorrsig::PublicKey, Vec<Announcement>), |
|
|
|
(lock_desc, lock_amount): (&Descriptor<PublicKey>, Amount), |
|
|
|
(commit_desc, commit_amount): (&Descriptor<PublicKey>, Amount), |
|
|
|
) { |
|
|
@ -460,8 +496,19 @@ fn verify_cfd_sigs( |
|
|
|
&taker_pk.key, |
|
|
|
) |
|
|
|
.expect("valid taker refund sig"); |
|
|
|
for (tx, _, digits) in taker_cfd_txs.cets.iter() { |
|
|
|
maker_cfd_txs |
|
|
|
|
|
|
|
for grouped_taker_cets in taker_cfd_txs.cets.iter() { |
|
|
|
let grouped_maker_cets = maker_cfd_txs |
|
|
|
.cets |
|
|
|
.iter() |
|
|
|
.find(|grouped_maker_cets| grouped_maker_cets.event == grouped_taker_cets.event) |
|
|
|
.expect("both parties to have the same set of payouts"); |
|
|
|
let event = events |
|
|
|
.iter() |
|
|
|
.find(|event| event.id == grouped_maker_cets.event.id) |
|
|
|
.expect("event to exist"); |
|
|
|
for (tx, _, digits) in grouped_taker_cets.cets.iter() { |
|
|
|
grouped_maker_cets |
|
|
|
.cets |
|
|
|
.iter() |
|
|
|
.find(|(maker_tx, maker_encsig, _)| { |
|
|
@ -471,7 +518,7 @@ fn verify_cfd_sigs( |
|
|
|
maker_encsig, |
|
|
|
digits, |
|
|
|
&maker_pk.key, |
|
|
|
(oracle_pk, nonce_pks), |
|
|
|
(oracle_pk, event.nonce_pks.as_slice()), |
|
|
|
commit_desc, |
|
|
|
commit_amount, |
|
|
|
) |
|
|
@ -479,8 +526,20 @@ fn verify_cfd_sigs( |
|
|
|
}) |
|
|
|
.expect("one valid maker cet encsig per cet"); |
|
|
|
} |
|
|
|
for (tx, _, msg_nonce_pairs) in maker_cfd_txs.cets.iter() { |
|
|
|
taker_cfd_txs |
|
|
|
} |
|
|
|
|
|
|
|
for grouped_maker_cets in maker_cfd_txs.cets.iter() { |
|
|
|
let grouped_taker_cets = taker_cfd_txs |
|
|
|
.cets |
|
|
|
.iter() |
|
|
|
.find(|grouped_taker_cets| grouped_taker_cets.event == grouped_maker_cets.event) |
|
|
|
.expect("both parties to have the same set of payouts"); |
|
|
|
let event = events |
|
|
|
.iter() |
|
|
|
.find(|event| event.id == grouped_maker_cets.event.id) |
|
|
|
.expect("event to exist"); |
|
|
|
for (tx, _, digits) in grouped_maker_cets.cets.iter() { |
|
|
|
grouped_taker_cets |
|
|
|
.cets |
|
|
|
.iter() |
|
|
|
.find(|(taker_tx, taker_encsig, _)| { |
|
|
@ -488,9 +547,9 @@ fn verify_cfd_sigs( |
|
|
|
&& verify_cet_encsig( |
|
|
|
tx, |
|
|
|
taker_encsig, |
|
|
|
msg_nonce_pairs, |
|
|
|
digits, |
|
|
|
&taker_pk.key, |
|
|
|
(oracle_pk, nonce_pks), |
|
|
|
(oracle_pk, event.nonce_pks.as_slice()), |
|
|
|
commit_desc, |
|
|
|
commit_amount, |
|
|
|
) |
|
|
@ -498,6 +557,8 @@ fn verify_cfd_sigs( |
|
|
|
}) |
|
|
|
.expect("one valid taker cet encsig per cet"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
encverify_spend( |
|
|
|
&taker_cfd_txs.commit.0, |
|
|
|
&maker_cfd_txs.commit.1, |
|
|
@ -557,7 +618,7 @@ fn check_cfd_txs( |
|
|
|
SecretKey, |
|
|
|
Address, |
|
|
|
), |
|
|
|
oracle_data: OliviaData, |
|
|
|
oracle_data_list: &[OliviaData], |
|
|
|
(lock_desc, lock_amount): (Descriptor<PublicKey>, Amount), |
|
|
|
(commit_desc, commit_amount): (Descriptor<PublicKey>, Amount), |
|
|
|
) { |
|
|
@ -604,51 +665,77 @@ fn check_cfd_txs( |
|
|
|
|
|
|
|
// CETs:
|
|
|
|
|
|
|
|
let unlocked_cets = maker_cfd_txs.cets.clone().into_iter().filter_map({ |
|
|
|
|(tx, _, digits)| { |
|
|
|
for Cets { event, cets } in maker_cfd_txs.cets.clone().into_iter() { |
|
|
|
let oracle_data = oracle_data_list |
|
|
|
.iter() |
|
|
|
.find(|data| data.id == event.id) |
|
|
|
.expect("every cet to correspond to an existing event"); |
|
|
|
let price = oracle_data.price; |
|
|
|
let oracle_attestations = oracle_data.attestations.clone(); |
|
|
|
|
|
|
|
let taker_cets = taker_cfd_txs |
|
|
|
.cets |
|
|
|
.iter() |
|
|
|
.find_map( |
|
|
|
|Cets { |
|
|
|
event: other_event, |
|
|
|
cets, |
|
|
|
}| (other_event.id == event.id).then(|| cets), |
|
|
|
) |
|
|
|
.expect("same events for taker and maker"); |
|
|
|
|
|
|
|
cets.into_iter().for_each(|(tx, _, digits)| { |
|
|
|
if !digits.range().contains(&price) { |
|
|
|
return None; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
let oracle_attestations = oracle_data.attestations.clone(); |
|
|
|
build_and_check_cet( |
|
|
|
tx, |
|
|
|
&taker_cfd_txs.cets, |
|
|
|
taker_cets, |
|
|
|
(&maker_sk, &maker_pk), |
|
|
|
&taker_pk, |
|
|
|
(price, &oracle_attestations), |
|
|
|
(&signed_commit_tx_maker, &commit_desc, commit_amount), |
|
|
|
) |
|
|
|
.expect("valid maker cet"); |
|
|
|
|
|
|
|
Some(()) |
|
|
|
} |
|
|
|
.expect("valid unlocked maker cet"); |
|
|
|
}); |
|
|
|
assert_eq!(unlocked_cets.count(), 1, "Expected to unlock only 1 CET"); |
|
|
|
} |
|
|
|
|
|
|
|
let unlocked_cets = taker_cfd_txs |
|
|
|
.cets |
|
|
|
.into_iter() |
|
|
|
.filter_map(|(tx, _, digits)| { |
|
|
|
for Cets { event, cets } in taker_cfd_txs.cets.clone().into_iter() { |
|
|
|
let oracle_data = oracle_data_list |
|
|
|
.iter() |
|
|
|
.find(|data| data.id == event.id) |
|
|
|
.expect("every cet to correspond to an existing event"); |
|
|
|
let price = oracle_data.price; |
|
|
|
let oracle_attestations = oracle_data.attestations.clone(); |
|
|
|
|
|
|
|
let maker_cets = maker_cfd_txs |
|
|
|
.cets |
|
|
|
.iter() |
|
|
|
.find_map( |
|
|
|
|Cets { |
|
|
|
event: other_event, |
|
|
|
cets, |
|
|
|
}| (other_event.id == event.id).then(|| cets), |
|
|
|
) |
|
|
|
.expect("same events for taker and maker"); |
|
|
|
|
|
|
|
cets.into_iter().for_each(|(tx, _, digits)| { |
|
|
|
if !digits.range().contains(&price) { |
|
|
|
return None; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
build_and_check_cet( |
|
|
|
tx, |
|
|
|
&maker_cfd_txs.cets, |
|
|
|
maker_cets, |
|
|
|
(&taker_sk, &taker_pk), |
|
|
|
&maker_pk, |
|
|
|
(price, &oracle_data.attestations), |
|
|
|
(&signed_commit_tx_maker, &commit_desc, commit_amount), |
|
|
|
(price, &oracle_attestations), |
|
|
|
(&signed_commit_tx_taker, &commit_desc, commit_amount), |
|
|
|
) |
|
|
|
.expect("valid taker cet"); |
|
|
|
|
|
|
|
Some(()) |
|
|
|
.expect("valid unlocked taker cet"); |
|
|
|
}); |
|
|
|
assert_eq!(unlocked_cets.count(), 1, "Expected to unlock only 1 CET"); |
|
|
|
} |
|
|
|
|
|
|
|
// Punish transactions:
|
|
|
|
|
|
|
@ -930,6 +1017,7 @@ fn make_keypair(rng: &mut (impl RngCore + CryptoRng)) -> (SecretKey, PublicKey) |
|
|
|
} |
|
|
|
|
|
|
|
struct OliviaData { |
|
|
|
id: String, |
|
|
|
pk: schnorrsig::PublicKey, |
|
|
|
nonce_pks: Vec<schnorrsig::PublicKey>, |
|
|
|
price: u64, |
|
|
@ -937,18 +1025,65 @@ struct OliviaData { |
|
|
|
} |
|
|
|
|
|
|
|
impl OliviaData { |
|
|
|
fn example_0() -> Self { |
|
|
|
Self::example( |
|
|
|
Self::EVENT_ID_0, |
|
|
|
Self::PRICE_0, |
|
|
|
&Self::NONCE_PKS_0, |
|
|
|
&Self::ATTESTATIONS_0, |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
fn example_1() -> Self { |
|
|
|
Self::example( |
|
|
|
Self::EVENT_ID_1, |
|
|
|
Self::PRICE_1, |
|
|
|
&Self::NONCE_PKS_1, |
|
|
|
&Self::ATTESTATIONS_1, |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
/// An example of all the data necessary from `olivia` to test the
|
|
|
|
/// CFD protocol.
|
|
|
|
///
|
|
|
|
/// Data comes from this event:
|
|
|
|
/// https://outcome.observer/h00.ooo/x/BitMEX/BXBT/2021-10-05T02:00:00.price[n:20].
|
|
|
|
pub fn example() -> Self { |
|
|
|
let pk = schnorrsig::PublicKey::from_str( |
|
|
|
"ddd4636845a90185991826be5a494cde9f4a6947b1727217afedc6292fa4caf7", |
|
|
|
) |
|
|
|
.unwrap(); |
|
|
|
fn example(id: &str, price: u64, nonce_pks: &[&str], attestations: &[&str]) -> Self { |
|
|
|
let oracle_pk = schnorrsig::PublicKey::from_str(Self::OLIVIA_PK).unwrap(); |
|
|
|
|
|
|
|
let id = id.to_string(); |
|
|
|
|
|
|
|
let nonce_pks = nonce_pks |
|
|
|
.iter() |
|
|
|
.map(|pk| schnorrsig::PublicKey::from_str(pk).unwrap()) |
|
|
|
.collect(); |
|
|
|
|
|
|
|
let attestations = attestations |
|
|
|
.iter() |
|
|
|
.map(|pk| SecretKey::from_str(pk).unwrap()) |
|
|
|
.collect(); |
|
|
|
|
|
|
|
Self { |
|
|
|
id, |
|
|
|
pk: oracle_pk, |
|
|
|
nonce_pks, |
|
|
|
attestations, |
|
|
|
price, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fn announcement(&self) -> Announcement { |
|
|
|
Announcement { |
|
|
|
id: self.id.clone(), |
|
|
|
nonce_pks: self.nonce_pks.clone(), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
let nonce_pks = [ |
|
|
|
const OLIVIA_PK: &'static str = |
|
|
|
"ddd4636845a90185991826be5a494cde9f4a6947b1727217afedc6292fa4caf7"; |
|
|
|
|
|
|
|
const EVENT_ID_0: &'static str = "/x/BitMEX/BXBT/2021-10-05T02:00:00.price[n:20]"; |
|
|
|
const NONCE_PKS_0: [&'static str; 20] = [ |
|
|
|
"d02d163cf9623f567c4e3faf851a9266ac1ede13da4ca4141f3a7717fba9a739", |
|
|
|
"bc310f26aa5addbc382f653d8530aaead7c25e3546abc24639f490e36d4bdb88", |
|
|
|
"2661375f570dcc32300d442e85b6d72dfa3232dccda45e8fb4a2d1e758d1d374", |
|
|
@ -969,12 +1104,9 @@ impl OliviaData { |
|
|
|
"763009afb0ffd99c7b835488cb3b0302f3b78f59bbfd5292bedab8ef9da8c1b7", |
|
|
|
"3867af9048309a05004a164bdea09899f23ff1d83b6491b2b53a1b7b92e0eb2e", |
|
|
|
"688118e6b59e27944c277513db2711a520f4283c7c53a11f58d9f6a46d82c964", |
|
|
|
] |
|
|
|
.iter() |
|
|
|
.map(|pk| schnorrsig::PublicKey::from_str(pk).unwrap()) |
|
|
|
.collect(); |
|
|
|
|
|
|
|
let attestations = [ |
|
|
|
]; |
|
|
|
const PRICE_0: u64 = 49262; |
|
|
|
const ATTESTATIONS_0: [&'static str; 20] = [ |
|
|
|
"5bc7663195971daaa1e3e6a81b4bca65882791644bc446fc060cbc118a3ace0f", |
|
|
|
"721d0cb56a0778a1ca7907f81a0787f34385b13f854c845c4c5539f7f6267958", |
|
|
|
"044aeef0d525c8ff48758c80939e95807bc640990cc03f53ab6fc0b262045221", |
|
|
@ -995,16 +1127,61 @@ impl OliviaData { |
|
|
|
"0818c9c245d7d2162cd393c562a121f80405a27d22ae465e95030c31ebb4bd24", |
|
|
|
"b7c03f0bd6d63bd78ad4ea0f3452ff9717ba65ca42038e6e90a1aa558b7942dc", |
|
|
|
"90c4d8ec9f408ccb62a62daa993c20f2f86799e1fdea520c6d060418e55fd216", |
|
|
|
] |
|
|
|
.iter() |
|
|
|
.map(|pk| SecretKey::from_str(pk).unwrap()) |
|
|
|
.collect(); |
|
|
|
|
|
|
|
Self { |
|
|
|
pk, |
|
|
|
nonce_pks, |
|
|
|
attestations, |
|
|
|
price: 49262, |
|
|
|
} |
|
|
|
]; |
|
|
|
|
|
|
|
const EVENT_ID_1: &'static str = "/x/BitMEX/BXBT/2021-10-05T08:00:00.price[n:20]"; |
|
|
|
const NONCE_PKS_1: [&'static str; 20] = [ |
|
|
|
"150df2e64f39706e726eaa1fe081af3edf376d9644723e135a99328fd194caca", |
|
|
|
"b90629cedc7cb8430b4d15c84bbe1fe173e70e626d40c465e64de29d4879e20f", |
|
|
|
"ae14ffb8701d3e224b6632a1bb7b099c8aa90979c3fb788422daa08bca25fa68", |
|
|
|
"3717940a7e8c35b48b3596498ed93e4d54ba01a2bcbb645d30dae2fc98f087a8", |
|
|
|
"91beb5da91cc8b4ee6ae603e7ae41cc041d5ea2c13bae9f0e630c69f6c0adfad", |
|
|
|
"c51cafb450b01f30ec8bd2b4b5fed6f7e179f49945959f0d7609b4b9c5ab3781", |
|
|
|
"75f2d9332aa1b2d84446a4b2aa276b4c2853659ab0ba74f0881289d3ab700f0c", |
|
|
|
"5367de73acb53e69b0a4f777e564f87055fede5d4492ddafae876a815fa6166c", |
|
|
|
"2087a513adb1aa2cc8506ca58306723ed13ba82e054f5bf29fcbeef1ab915c5a", |
|
|
|
"71c980fb6adae9c121405628c91daffcc5ab52a8a0b6f53c953e8a0236b05782", |
|
|
|
"d370d22f06751fc649f6ee930ac7f8f3b00389fdad02883a8038a81c46c33b19", |
|
|
|
"fa6f7d37dc88b510c250dcae1023cce5009d5beb85a75f5b8b10c973b62348aa", |
|
|
|
"a658077f9c963d1f41cf63b7ebf6e08331f5d201554b3af7814673108abe1bf3", |
|
|
|
"8a816bf4caa2d6114b2e4d3ab9bff0d470ee0b90163c78c9b67f90238ead9319", |
|
|
|
"c2519a4e764a65204c469062e260d8565f7730847c507b92c987e478ca91abe1", |
|
|
|
"59cb6b5beac6511a671076530cc6cc9f1926f54c640828f38c363b110dd8a0cd", |
|
|
|
"4625b1f3ab9ee01455fa1a98d15fc8d73a7cf41becb4ca5c6eab88db0ba7c114", |
|
|
|
"82a4de403c604fe40aa3804c5ada6af54c425c0576980b50f259d32dc1a0fcff", |
|
|
|
"5c4fb87b3812982759ed7264676e713e4e477a41759261515b04797db393ef62", |
|
|
|
"f3f6b9134c0fdd670767fbf478fd0dd3430f195ce9c21cabb84f3c1dd4848a11", |
|
|
|
]; |
|
|
|
const PRICE_1: u64 = 49493; |
|
|
|
const ATTESTATIONS_1: [&'static str; 20] = [ |
|
|
|
"605f458e9a7bd216ff522e45f6cd14378c03ccfd4d35a69b9b6ce5c4ebfc89fa", |
|
|
|
"edc7215277d2c24a7a4659ff8831352db609fcc467fead5e27fdada172cdfd86", |
|
|
|
"1c2d76fcbe724b1fabd2622b991e90bbb2ea9244489de960747134c9fd695dcb", |
|
|
|
"26b4f078c9ca2233b18b0e42c4bb9867e5de8ee35b500e30b28d9b1742322e49", |
|
|
|
"2b59aeaacb80056b45dc12d6525d5c75343ef75730623c8d9893e2b681bf4b85", |
|
|
|
"782e38e777d527e7cb0028a6d03e8f760c6202dbc5ac605f67f995919dee6182", |
|
|
|
"a902f37f71a78e4bcf431a778024bd775db6d7ade0626a9e7bc4cdf0b1e52dfd", |
|
|
|
"3927eb5ef3b56817c08709e0af1bb643ad4d95dbf5a92a49e1e9c8c811e929c4", |
|
|
|
"9ff44fa9d8377a3531792cd6362e4a5b24b86d85602749d301f8449859065b77", |
|
|
|
"6a2156ff0aaef174b36d5f8adc597fdcb26f306f7ef6e9a485faabc8eb29da2e", |
|
|
|
"53445b507c0de312959fe4566b82db93987dd0b854f1a33bbad7768512bcaf69", |
|
|
|
"793c40e0ec3a830c46658bfaed7df74e3fc6781e421e00db5b5f46b26ce4d092", |
|
|
|
"db7f800da2f22878c8fc8368047308146e1ebd6316c389303c07ebeed7488fc9", |
|
|
|
"73921d09e0d567a03f3a411c0f3455f9f652bbede808a694cca0fa94619f5ba9", |
|
|
|
"3d4bd70d93f20aa6b1621ccd077c90bcdee47ce2bae15155434a77a3153a3235", |
|
|
|
"90fc10577ab737e311b43288a266490f222a6ecb9f9667e01d7a54c0437d145f", |
|
|
|
"51d350616c6fdf90254240b757184fc0dd226328adb42be214ec25832854950e", |
|
|
|
"bab3a6269e172ac590fd36683724f087b4add293bb0ee4ef3d21fb5929985c75", |
|
|
|
"d65a4c71062fc0b0210bb3e239f60d826a37d28caadfc52edd7afde6e91ff818", |
|
|
|
"ea5dfd972784808a15543f850c7bc86bff2b51cff81ec68fc4c3977d5e7d38de", |
|
|
|
]; |
|
|
|
} |
|
|
|
|
|
|
|
fn assert_contains_cets_for_event(cets: &[Cets], event: &Announcement) { |
|
|
|
assert!(!cets |
|
|
|
.iter() |
|
|
|
.find(|cet| cet.event.id == event.id) |
|
|
|
.expect("cet to correspond to existing event") |
|
|
|
.cets |
|
|
|
.is_empty()); |
|
|
|
} |
|
|
|