mirror of
https://github.com/conduition/dlctix.git
synced 2026-02-23 00:44:43 +01:00
abstract event announcement away as an array of locking points
To support digit decomposition events, dlctix will represent the oracle event data as an array of locking points, each representing a different outcome in the DLC. Enum events can be easily converted into a set of locking points. Digit decomp events can also be likewise converted, by enumerating the set of relevant digit ranges, and aggregating sets of locking points together. As a bonus, this also adds support for multi-oracle DLCs, as oracle locking points from different oracles can also be safely aggregated.
This commit is contained in:
@@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
consts::{P2TR_DUST_VALUE, P2TR_SCRIPT_PUBKEY_SIZE},
|
||||
errors::Error,
|
||||
oracles::EventAnnouncement,
|
||||
oracles::EventLockingConditions,
|
||||
parties::{MarketMaker, Player},
|
||||
spend_info::FundingSpendInfo,
|
||||
};
|
||||
@@ -53,10 +53,10 @@ pub struct ContractParameters {
|
||||
pub players: Vec<Player>,
|
||||
|
||||
/// The event whose outcome determines the payouts.
|
||||
pub event: EventAnnouncement,
|
||||
pub event: EventLockingConditions,
|
||||
|
||||
/// A mapping of payout weights under different outcomes. Attestation indexes should
|
||||
/// align with [`self.event.outcome_messages`][EventAnnouncement::outcome_messages].
|
||||
/// align with [`self.event.locking_points`][EventLockingConditions::locking_points].
|
||||
///
|
||||
// The outcome payouts map describes how payouts are allocated based on the Outcome
|
||||
// which has been attested to by the oracle. If the oracle doesn't attest to any
|
||||
|
||||
@@ -136,7 +136,8 @@ pub(crate) fn partial_sign_outcome_txs(
|
||||
// All outcome TX signatures should be locked by the oracle's outcome point.
|
||||
let attestation_lock_point = params
|
||||
.event
|
||||
.attestation_lock_point(outcome_index)
|
||||
.locking_points
|
||||
.get(outcome_index)
|
||||
.ok_or(Error)?;
|
||||
|
||||
// sign under an attestation lock point
|
||||
@@ -145,7 +146,7 @@ pub(crate) fn partial_sign_outcome_txs(
|
||||
seckey,
|
||||
secnonce,
|
||||
aggnonce,
|
||||
attestation_lock_point,
|
||||
*attestation_lock_point,
|
||||
sighash,
|
||||
)?
|
||||
}
|
||||
@@ -189,14 +190,15 @@ pub(crate) fn verify_outcome_tx_partial_signatures(
|
||||
// All outcome TX signatures should be locked by the oracle's outcome point.
|
||||
let attestation_lock_point = params
|
||||
.event
|
||||
.attestation_lock_point(outcome_index)
|
||||
.locking_points
|
||||
.get(outcome_index)
|
||||
.ok_or(Error)?;
|
||||
|
||||
musig2::adaptor::verify_partial(
|
||||
funding_spend_info.key_agg_ctx(),
|
||||
partial_sig,
|
||||
aggnonce,
|
||||
attestation_lock_point,
|
||||
*attestation_lock_point,
|
||||
signer_pubkey,
|
||||
pubnonce,
|
||||
sighash,
|
||||
@@ -273,13 +275,14 @@ where
|
||||
Outcome::Attestation(outcome_index) => {
|
||||
let attestation_lock_point = params
|
||||
.event
|
||||
.attestation_lock_point(outcome_index)
|
||||
.locking_points
|
||||
.get(outcome_index)
|
||||
.ok_or(Error)?;
|
||||
|
||||
let adaptor_sig = musig2::adaptor::aggregate_partial_signatures(
|
||||
funding_spend_info.key_agg_ctx(),
|
||||
aggnonce,
|
||||
attestation_lock_point,
|
||||
*attestation_lock_point,
|
||||
partial_sigs,
|
||||
sighash,
|
||||
)?;
|
||||
@@ -342,7 +345,8 @@ pub(crate) fn verify_outcome_tx_aggregated_signatures(
|
||||
Outcome::Attestation(outcome_index) => {
|
||||
let adaptor_point = params
|
||||
.event
|
||||
.attestation_lock_point(outcome_index)
|
||||
.locking_points
|
||||
.get(outcome_index)
|
||||
.ok_or(Error)?;
|
||||
|
||||
let &signature = outcome_tx_signatures.get(&outcome_index).ok_or(Error)?;
|
||||
@@ -350,7 +354,7 @@ pub(crate) fn verify_outcome_tx_aggregated_signatures(
|
||||
joint_pubkey,
|
||||
sighash,
|
||||
signature,
|
||||
adaptor_point,
|
||||
*adaptor_point,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
13
src/lib.rs
13
src/lib.rs
@@ -42,7 +42,7 @@ use std::{
|
||||
pub use contract::{
|
||||
ContractParameters, Outcome, OutcomeIndex, PayoutWeights, PlayerIndex, SigMap, WinCondition,
|
||||
};
|
||||
pub use oracles::EventAnnouncement;
|
||||
pub use oracles::{attestation_locking_point, attestation_secret, EventLockingConditions};
|
||||
pub use parties::{MarketMaker, Player};
|
||||
|
||||
/// Represents the combined output of building all transactions and precomputing
|
||||
@@ -547,9 +547,9 @@ pub struct ContractSignatures {
|
||||
pub expiry_tx_signature: Option<CompactSignature>,
|
||||
/// A mapping of outcome attestation indexes to adaptor signatures on outcome transactions.
|
||||
/// The index of each entry corresponds to the outcomes in
|
||||
/// [`EventAnnouncement::outcome_messages`]. Each adaptor signature can be decrypted
|
||||
/// by the [`EventAnnouncement`]'s oracle producing an attestation signature using
|
||||
/// [`EventAnnouncement::attestation_secret`].
|
||||
/// [`EventLockingConditions::outcome_messages`]. Each adaptor signature can be decrypted
|
||||
/// by the [`EventLockingConditions`]'s oracle producing an attestation signature using
|
||||
/// [`EventLockingConditions::attestation_secret`].
|
||||
pub outcome_tx_signatures: BTreeMap<OutcomeIndex, AdaptorSignature>,
|
||||
/// A set of signatures needed for broadcasting split transactions. Each signature
|
||||
/// is specific to a certain combination of player and outcome.
|
||||
@@ -653,11 +653,12 @@ impl SignedContract {
|
||||
.dlc
|
||||
.params
|
||||
.event
|
||||
.attestation_lock_point(outcome_index)
|
||||
.locking_points
|
||||
.get(outcome_index)
|
||||
.ok_or(Error)?;
|
||||
|
||||
// Invalid attestation.
|
||||
if attestation.base_point_mul() != locking_point {
|
||||
if &attestation.base_point_mul() != locking_point {
|
||||
return Err(Error)?;
|
||||
}
|
||||
|
||||
|
||||
129
src/oracles.rs
129
src/oracles.rs
@@ -1,83 +1,96 @@
|
||||
use secp::{MaybePoint, MaybeScalar, Point, Scalar};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::{serialization, Outcome, OutcomeIndex};
|
||||
use crate::Outcome;
|
||||
|
||||
/// An oracle's announcement of a future event.
|
||||
/// The locking points derived from the oracle's announcement of a future event.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct EventAnnouncement {
|
||||
/// The signing oracle's pubkey
|
||||
pub oracle_pubkey: Point,
|
||||
|
||||
/// The `R` point with which the oracle promises to attest to this event.
|
||||
pub nonce_point: Point,
|
||||
|
||||
/// Naive but easy.
|
||||
#[serde(with = "serialization::vec_of_byte_vecs")]
|
||||
pub outcome_messages: Vec<Vec<u8>>,
|
||||
pub struct EventLockingConditions {
|
||||
/// An array of locking points which represent distinct outcomes. Each locking point
|
||||
/// should have its discrete log revealed by the oracle when and if that outcome occurs.
|
||||
pub locking_points: Vec<MaybePoint>,
|
||||
|
||||
/// The unix timestamp beyond which the oracle is considered to have gone AWOL.
|
||||
/// If set to `None`, the event has no expected expiry.
|
||||
pub expiry: Option<u32>,
|
||||
}
|
||||
|
||||
impl EventAnnouncement {
|
||||
/// Computes the oracle's locking point for the given outcome index.
|
||||
pub fn attestation_lock_point(&self, index: OutcomeIndex) -> Option<MaybePoint> {
|
||||
let msg = &self.outcome_messages.get(index)?;
|
||||
|
||||
let e: MaybeScalar = musig2::compute_challenge_hash_tweak(
|
||||
&self.nonce_point.serialize_xonly(),
|
||||
&self.oracle_pubkey,
|
||||
msg,
|
||||
);
|
||||
|
||||
// S = R + eD
|
||||
Some(self.nonce_point.to_even_y() + e * self.oracle_pubkey.to_even_y())
|
||||
}
|
||||
|
||||
/// Computes the oracle's attestation secret scalar - the discrete log of the
|
||||
/// locking point - for the given outcome index.
|
||||
pub fn attestation_secret(
|
||||
&self,
|
||||
index: usize,
|
||||
oracle_seckey: impl Into<Scalar>,
|
||||
nonce: impl Into<Scalar>,
|
||||
) -> Option<MaybeScalar> {
|
||||
let oracle_seckey = oracle_seckey.into();
|
||||
let nonce = nonce.into();
|
||||
|
||||
if oracle_seckey.base_point_mul() != self.oracle_pubkey
|
||||
|| nonce.base_point_mul() != self.nonce_point
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let d = oracle_seckey.negate_if(self.oracle_pubkey.parity());
|
||||
let k = nonce.negate_if(self.nonce_point.parity());
|
||||
|
||||
let msg = &self.outcome_messages.get(index)?;
|
||||
let e: MaybeScalar = musig2::compute_challenge_hash_tweak(
|
||||
&self.nonce_point.serialize_xonly(),
|
||||
&self.oracle_pubkey,
|
||||
msg,
|
||||
);
|
||||
Some(k + e * d)
|
||||
}
|
||||
|
||||
impl EventLockingConditions {
|
||||
/// Returns true if the given outcome is a valid outcome to wager on
|
||||
/// for this event.
|
||||
pub fn is_valid_outcome(&self, outcome: &Outcome) -> bool {
|
||||
match outcome {
|
||||
&Outcome::Attestation(i) => i < self.outcome_messages.len(),
|
||||
&Outcome::Attestation(i) => i < self.locking_points.len(),
|
||||
Outcome::Expiry => self.expiry.is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over all possible outcomes in the event.
|
||||
pub fn all_outcomes(&self) -> impl IntoIterator<Item = Outcome> {
|
||||
(0..self.outcome_messages.len())
|
||||
(0..self.locking_points.len())
|
||||
.map(|i| Outcome::Attestation(i))
|
||||
.chain(self.expiry.map(|_| Outcome::Expiry))
|
||||
}
|
||||
}
|
||||
|
||||
fn tagged_hash(tag: &str) -> Sha256 {
|
||||
let tag_hash = Sha256::new().chain_update(tag).finalize();
|
||||
Sha256::new()
|
||||
.chain_update(&tag_hash)
|
||||
.chain_update(&tag_hash)
|
||||
}
|
||||
|
||||
pub(crate) fn outcome_message_hash(msg: impl AsRef<[u8]>) -> [u8; 32] {
|
||||
tagged_hash("DLC/oracle/attestation/v0")
|
||||
.chain_update(msg)
|
||||
.finalize()
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Computes the attestation locking point given an oracle pubkey, nonce, and message.
|
||||
#[allow(non_snake_case)]
|
||||
pub fn attestation_locking_point(
|
||||
oracle_pubkey: impl Into<Point>,
|
||||
nonce: impl Into<Point>,
|
||||
message: impl AsRef<[u8]>,
|
||||
) -> MaybePoint {
|
||||
let oracle_pubkey = oracle_pubkey.into();
|
||||
let nonce = nonce.into();
|
||||
|
||||
let R = nonce.to_even_y();
|
||||
let D = oracle_pubkey.to_even_y();
|
||||
|
||||
let e: MaybeScalar = musig2::compute_challenge_hash_tweak(
|
||||
&nonce.serialize_xonly(),
|
||||
&oracle_pubkey,
|
||||
outcome_message_hash(message),
|
||||
);
|
||||
|
||||
// S = R + eD
|
||||
R + e * D
|
||||
}
|
||||
|
||||
/// Computes the oracle's attestation secret scalar - the discrete log of the
|
||||
/// locking point - for the given outcome message.
|
||||
pub fn attestation_secret(
|
||||
oracle_seckey: impl Into<Scalar>,
|
||||
nonce: impl Into<Scalar>,
|
||||
message: impl AsRef<[u8]>,
|
||||
) -> MaybeScalar {
|
||||
let oracle_seckey = oracle_seckey.into();
|
||||
let nonce = nonce.into();
|
||||
|
||||
let oracle_pubkey = oracle_seckey.base_point_mul();
|
||||
let nonce_point = nonce.base_point_mul();
|
||||
|
||||
let d = oracle_seckey.negate_if(oracle_pubkey.parity());
|
||||
let k = nonce.negate_if(nonce_point.parity());
|
||||
|
||||
let e: MaybeScalar = musig2::compute_challenge_hash_tweak(
|
||||
&nonce_point.serialize_xonly(),
|
||||
&oracle_pubkey,
|
||||
outcome_message_hash(message),
|
||||
);
|
||||
k + e * d
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use bitcoin::{
|
||||
};
|
||||
use musig2::{CompactSignature, LiftedSignature, PartialSignature, PubNonce};
|
||||
use rand::{CryptoRng, Rng, RngCore, SeedableRng};
|
||||
use secp::{MaybeScalar, Point, Scalar};
|
||||
use secp::{MaybePoint, MaybeScalar, Point, Scalar};
|
||||
|
||||
use bitcoincore_rpc::{jsonrpc::serde_json, Auth, Client as BitcoinClient, RpcApi};
|
||||
use once_cell::sync::Lazy;
|
||||
@@ -412,6 +412,7 @@ struct SimulationManager {
|
||||
market_maker_seckey: Scalar,
|
||||
oracle_seckey: Scalar,
|
||||
oracle_secnonce: Scalar,
|
||||
outcome_messages: Vec<Vec<u8>>,
|
||||
|
||||
contract: SignedContract,
|
||||
rpc: BitcoinClient,
|
||||
@@ -429,6 +430,17 @@ impl SimulationManager {
|
||||
// Oracle
|
||||
let oracle_seckey = Scalar::random(&mut rng);
|
||||
let oracle_secnonce = Scalar::random(&mut rng);
|
||||
let oracle_pubkey = oracle_seckey.base_point_mul();
|
||||
let nonce_point = oracle_secnonce.base_point_mul();
|
||||
let outcome_messages = vec![
|
||||
Vec::from(b"alice, bob, and carol win"),
|
||||
Vec::from(b"bob and carol win"),
|
||||
Vec::from(b"alice wins"),
|
||||
];
|
||||
let locking_points: Vec<MaybePoint> = outcome_messages
|
||||
.iter()
|
||||
.map(|msg| attestation_locking_point(oracle_pubkey, nonce_point, msg))
|
||||
.collect();
|
||||
|
||||
// Market maker
|
||||
let market_maker_seckey = Scalar::random(&mut rng);
|
||||
@@ -493,14 +505,8 @@ impl SimulationManager {
|
||||
let contract_params = ContractParameters {
|
||||
market_maker,
|
||||
players,
|
||||
event: EventAnnouncement {
|
||||
oracle_pubkey: oracle_seckey.base_point_mul(),
|
||||
nonce_point: oracle_secnonce.base_point_mul(),
|
||||
outcome_messages: vec![
|
||||
Vec::from(b"alice, bob, and carol win"),
|
||||
Vec::from(b"bob and carol win"),
|
||||
Vec::from(b"alice wins"),
|
||||
],
|
||||
event: EventLockingConditions {
|
||||
locking_points,
|
||||
expiry: u32::try_from(initial_block_height + 100).ok(),
|
||||
},
|
||||
outcome_payouts,
|
||||
@@ -554,6 +560,7 @@ impl SimulationManager {
|
||||
market_maker_seckey,
|
||||
oracle_seckey,
|
||||
oracle_secnonce,
|
||||
outcome_messages,
|
||||
|
||||
contract: signed_contract,
|
||||
rpc,
|
||||
@@ -562,13 +569,16 @@ impl SimulationManager {
|
||||
}
|
||||
}
|
||||
|
||||
fn event(&self) -> &EventAnnouncement {
|
||||
fn event(&self) -> &EventLockingConditions {
|
||||
&self.contract.params().event
|
||||
}
|
||||
|
||||
fn oracle_attestation(&self, outcome_index: OutcomeIndex) -> Option<MaybeScalar> {
|
||||
self.event()
|
||||
.attestation_secret(outcome_index, self.oracle_seckey, self.oracle_secnonce)
|
||||
Some(attestation_secret(
|
||||
self.oracle_seckey,
|
||||
self.oracle_secnonce,
|
||||
self.outcome_messages.get(outcome_index)?,
|
||||
))
|
||||
}
|
||||
|
||||
fn mine_delta_blocks(&self) -> Result<(), bitcoincore_rpc::Error> {
|
||||
@@ -614,11 +624,11 @@ fn with_on_chain_resolutions() {
|
||||
// The attestation should be a valid BIP340 signature by the oracle's pubkey.
|
||||
{
|
||||
let oracle_signature =
|
||||
LiftedSignature::new(manager.event().nonce_point, oracle_attestation);
|
||||
LiftedSignature::new(manager.oracle_secnonce.base_point_mul(), oracle_attestation);
|
||||
musig2::verify_single(
|
||||
manager.event().oracle_pubkey,
|
||||
manager.oracle_seckey.base_point_mul(),
|
||||
oracle_signature,
|
||||
&manager.event().outcome_messages[outcome_index],
|
||||
crate::oracles::outcome_message_hash(&manager.outcome_messages[outcome_index]),
|
||||
)
|
||||
.expect("invalid oracle signature");
|
||||
}
|
||||
@@ -1313,6 +1323,8 @@ fn stress_test() {
|
||||
// Oracle
|
||||
let oracle_seckey = Scalar::random(&mut rng);
|
||||
let oracle_secnonce = Scalar::random(&mut rng);
|
||||
let oracle_pubkey = oracle_seckey.base_point_mul();
|
||||
let nonce_point = oracle_secnonce.base_point_mul();
|
||||
|
||||
// Market maker
|
||||
let market_maker_seckey = Scalar::random(&mut rng);
|
||||
@@ -1326,6 +1338,11 @@ fn stress_test() {
|
||||
.map(|i| Vec::from((i as u32).to_be_bytes()))
|
||||
.collect();
|
||||
|
||||
let locking_points: Vec<MaybePoint> = outcome_messages
|
||||
.iter()
|
||||
.map(|msg| attestation_locking_point(oracle_pubkey, nonce_point, msg))
|
||||
.collect();
|
||||
|
||||
// Generate random payouts with 4 winners per outcome
|
||||
let outcome_payouts: BTreeMap<Outcome, PayoutWeights> = (0..n_outcomes)
|
||||
.map(|i| {
|
||||
@@ -1344,10 +1361,8 @@ fn stress_test() {
|
||||
let contract_params = ContractParameters {
|
||||
market_maker,
|
||||
players,
|
||||
event: EventAnnouncement {
|
||||
oracle_pubkey: oracle_seckey.base_point_mul(),
|
||||
nonce_point: oracle_secnonce.base_point_mul(),
|
||||
outcome_messages,
|
||||
event: EventLockingConditions {
|
||||
locking_points,
|
||||
expiry: None,
|
||||
},
|
||||
outcome_payouts,
|
||||
|
||||
@@ -157,38 +157,10 @@ pub(crate) mod byte_array {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod vec_of_byte_vecs {
|
||||
use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serdect::slice::HexOrBin;
|
||||
|
||||
pub(crate) fn serialize<S: Serializer>(vecs: &Vec<Vec<u8>>, ser: S) -> Result<S::Ok, S::Error> {
|
||||
if !ser.is_human_readable() {
|
||||
return vecs.serialize(ser);
|
||||
}
|
||||
let mut seq = ser.serialize_seq(Some(vecs.len()))?;
|
||||
for vec in vecs {
|
||||
let slice: &[u8] = vec.as_ref();
|
||||
seq.serialize_element(&hex::encode(slice))?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
|
||||
pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
|
||||
deserializer: D,
|
||||
) -> Result<Vec<Vec<u8>>, D::Error> {
|
||||
Ok(
|
||||
Vec::<serdect::slice::HexOrBin<false>>::deserialize(deserializer)?
|
||||
.into_iter()
|
||||
.map(|HexOrBin(vec)| vec)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{EventAnnouncement, MarketMaker, PayoutWeights, Player};
|
||||
use crate::{EventLockingConditions, MarketMaker, PayoutWeights, Player};
|
||||
|
||||
use bitcoin::{Amount, FeeRate};
|
||||
use hex::ToHex;
|
||||
@@ -241,17 +213,14 @@ mod tests {
|
||||
payout_hash: [40; 32],
|
||||
},
|
||||
],
|
||||
event: EventAnnouncement {
|
||||
oracle_pubkey: "03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
nonce_point: "0317aec4eea8a2b02c38e6b67c26015d16c82a3a44abc28d1def124c1f79786fc5"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
outcome_messages: vec![
|
||||
Vec::from(b"option 1"),
|
||||
Vec::from(b"option 2"),
|
||||
Vec::from(b"option 3"),
|
||||
event: EventLockingConditions {
|
||||
locking_points: vec![
|
||||
"036b382e40647af612900fe6ad0aa0003790fef503ffa910c06d04811863d0791f"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
"038f7cd041cdf74616b9ce4837dbbc8a316e7f0150ab96419bd9a24db9b36e261d"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
],
|
||||
expiry: Some(u32::MAX),
|
||||
},
|
||||
@@ -289,12 +258,9 @@ mod tests {
|
||||
}
|
||||
],
|
||||
"event": {
|
||||
"oracle_pubkey": "03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7",
|
||||
"nonce_point": "0317aec4eea8a2b02c38e6b67c26015d16c82a3a44abc28d1def124c1f79786fc5",
|
||||
"outcome_messages": [
|
||||
"6f7074696f6e2031",
|
||||
"6f7074696f6e2032",
|
||||
"6f7074696f6e2033"
|
||||
"locking_points": [
|
||||
"036b382e40647af612900fe6ad0aa0003790fef503ffa910c06d04811863d0791f",
|
||||
"038f7cd041cdf74616b9ce4837dbbc8a316e7f0150ab96419bd9a24db9b36e261d"
|
||||
],
|
||||
"expiry": 4294967295
|
||||
},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use dlctix::bitcoin;
|
||||
use dlctix::musig2;
|
||||
use dlctix::secp::{Point, Scalar};
|
||||
use dlctix::secp::{MaybePoint, Point, Scalar};
|
||||
use dlctix::{
|
||||
hashlock, ContractParameters, ContributorPartialSignatureSharingRound, EventAnnouncement,
|
||||
hashlock, ContractParameters, ContributorPartialSignatureSharingRound, EventLockingConditions,
|
||||
MarketMaker, NonceSharingRound, Outcome, PayoutWeights, Player, SigMap, SignedContract,
|
||||
SigningSession, TicketedDLC, WinCondition,
|
||||
};
|
||||
@@ -59,22 +59,29 @@ fn two_player_example() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Oracles usually publish their announcements and attestations over
|
||||
// public mediums like a website, or Twitter, or Nostr.
|
||||
let oracle_seckey = Scalar::random(&mut rng);
|
||||
let oracle_pubkey = oracle_seckey.base_point_mul();
|
||||
|
||||
// Each event has an associated nonce which the oracle commits to
|
||||
// ahead of time.
|
||||
let oracle_secnonce = Scalar::random(&mut rng);
|
||||
let nonce_point = oracle_secnonce.base_point_mul();
|
||||
|
||||
// An announcement describes the different messages an oracle might sign.
|
||||
let event = EventAnnouncement {
|
||||
oracle_pubkey: oracle_seckey.base_point_mul(),
|
||||
nonce_point: oracle_secnonce.base_point_mul(),
|
||||
// We enumerate the different outcome messages the oracle could sign...
|
||||
let outcome_messages = vec![
|
||||
Vec::from(b"alice wins"),
|
||||
Vec::from(b"bob wins"),
|
||||
Vec::from(b"tie"),
|
||||
];
|
||||
|
||||
// We enumerate the different outcome messages the oracle could sign.
|
||||
outcome_messages: vec![
|
||||
Vec::from(b"alice wins"),
|
||||
Vec::from(b"bob wins"),
|
||||
Vec::from(b"tie"),
|
||||
],
|
||||
// ...and then precompute the locking points needed for each possible outcome.
|
||||
let locking_points: Vec<MaybePoint> = outcome_messages
|
||||
.iter()
|
||||
.map(|msg| dlctix::attestation_locking_point(oracle_pubkey, nonce_point, msg))
|
||||
.collect();
|
||||
|
||||
// This struct describes the different possible outcomes an oracle might sign.
|
||||
let event = EventLockingConditions {
|
||||
locking_points,
|
||||
|
||||
// The expiry time is the time after which the Expiry outcome transaction should be
|
||||
// triggered. This can either be a unix seconds timestamp, or a bitcoin block height,
|
||||
@@ -96,7 +103,7 @@ fn two_player_example() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let tie_payout = PayoutWeights::from([(0, 1), (1, 1)]); // split the pot evenly
|
||||
|
||||
// An Outcome is a compact representation of which of the messages in the
|
||||
// `EventAnnouncement::outcome_messages` field (if any) an oracle might attest
|
||||
// `EventLockingConditions::outcome_messages` field (if any) an oracle might attest
|
||||
// to.
|
||||
let alice_wins_outcome = Outcome::Attestation(0);
|
||||
let bob_wins_outcome = Outcome::Attestation(1);
|
||||
@@ -239,11 +246,11 @@ fn two_player_example() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//
|
||||
// However, before _any_ outcome can be enforced, the oracle must publish their attestation.
|
||||
let outcome_index = 0;
|
||||
let oracle_attestation = signed_contract
|
||||
.params()
|
||||
.event
|
||||
.attestation_secret(outcome_index, oracle_seckey, oracle_secnonce)
|
||||
.unwrap();
|
||||
let oracle_attestation = dlctix::attestation_secret(
|
||||
oracle_seckey,
|
||||
oracle_secnonce,
|
||||
&outcome_messages[outcome_index],
|
||||
);
|
||||
|
||||
// A win condition describes an outcome and a particular player
|
||||
// who is paid out under that outcome.
|
||||
|
||||
Reference in New Issue
Block a user