Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/dlcat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use bitcoin::opcodes::all::{OP_CHECKSIGVERIFY, OP_NOP4};
use bitcoin::script::PushBytesBuf;
use bitcoin::{
taproot::{TaprootBuilder, TaprootSpendInfo},
ScriptBuf,
ScriptBuf, TxOut,
};
use dlc::get_adaptor_point_from_oracle_info;
use dlc::secp256k1_zkp::{Message, Secp256k1, XOnlyPublicKey};
Expand All @@ -29,7 +29,11 @@ pub fn build_cat_taproot_leafs(
let msg = Message::from_hashed_data::<dlc::secp256k1_zkp::hashes::sha256::Hash>(
payout.outcome.as_bytes(),
);
let cat_script = op_cat_dlc_payout(&script_pubkey, payout.offer_payout);
let output = TxOut {
script_pubkey: script_pubkey.clone(),
value: payout.offer_payout,
};
let cat_script = op_cat_dlc_payout(&[output]);
builder = builder.add_leaf(depth, cat_script).unwrap();
}
}
Expand Down
98 changes: 51 additions & 47 deletions src/op_cat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ use crate::build_cat_taproot_leafs;
use crate::utils::create_nums_key;
use bitcoin::absolute::LockTime;
use bitcoin::consensus::Encodable;
use bitcoin::hashes::{sha256, Hash};
use bitcoin::key::Secp256k1;
use bitcoin::opcodes::all::{
OP_CAT, OP_CHECKSIG, OP_DUP, OP_EQUALVERIFY, OP_FROMALTSTACK, OP_ROT, OP_SHA256, OP_SWAP,
OP_TOALTSTACK,
};
use bitcoin::script::{Builder, PushBytesBuf};
use bitcoin::secp256k1::ThirtyTwoByteHash;
use bitcoin::sighash::TapSighashType;
use bitcoin::taproot::{LeafVersion, TapLeafHash, TaprootBuilder};
use bitcoin::{OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut};
Expand Down Expand Up @@ -80,13 +82,11 @@ pub(crate) fn create_cat_spending_tx(
};

let tx_commitment_spec = TxCommitmentSpec {
prev_sciptpubkeys: false,
prev_amounts: false,
outputs: false,
..Default::default()
};

let enforce_payout_spk = op_cat_dlc_payout(&output.script_pubkey, output.value);
let enforce_payout_spk = op_cat_dlc_payout(&[output.clone()]);

let leaf_hash = TapLeafHash::from_script(&enforce_payout_spk, LeafVersion::TapScript);
let contract_components =
Expand All @@ -113,22 +113,9 @@ pub(crate) fn create_cat_spending_tx(
let computed_signature =
compute_signature_from_components(&contract_components.signature_components)?;

let mut amount_buffer = Vec::new();
prev_output.value.consensus_encode(&mut amount_buffer)?;
collateral_txin.witness.push(amount_buffer.as_slice());
let mut scriptpubkey_buffer = Vec::new();
output
.script_pubkey
.consensus_encode(&mut scriptpubkey_buffer)?;
collateral_txin.witness.push(scriptpubkey_buffer.as_slice());

let mangled_signature: [u8; 63] = computed_signature[0..63].try_into().unwrap(); // chop off the last byte, so we can provide the 0x00 and 0x01 bytes on the stack
collateral_txin.witness.push(mangled_signature);

collateral_txin
.witness
.push(enforce_payout_spk.clone().to_bytes());

// Build the taproot tree of outcomes
let spend_info = build_cat_taproot_leafs(
outcomes,
Expand All @@ -144,6 +131,10 @@ pub(crate) fn create_cat_spending_tx(
// .finalize(&secp, create_nums_key())
// .unwrap();

collateral_txin
.witness
.push(enforce_payout_spk.clone().to_bytes());

collateral_txin.witness.push(
spend_info
.control_block(&(enforce_payout_spk.clone(), LeafVersion::TapScript))
Expand All @@ -160,55 +151,31 @@ pub(crate) struct ContractComponents {
pub(crate) signature_components: Vec<Vec<u8>>,
}

pub(crate) fn op_cat_dlc_payout(payout_spk: &ScriptBuf, amount: u64) -> ScriptBuf {
pub(crate) fn op_cat_dlc_payout(outputs: &[TxOut]) -> ScriptBuf {
let mut builder = Script::builder();
// The witness program needs to have the signature components except the outputs and the pre_scriptpubkeys and pre_amounts,
// followed by the output amount, then the script pubkey,
// followed by the fee amount, then the fee-paying scriptpubkey
// and finally the mangled signature

let payout_spk_bytes: PushBytesBuf = payout_spk.clone().into_bytes().try_into().unwrap();
let mut buffer = Vec::new();
for o in outputs {
o.consensus_encode(&mut buffer).unwrap();
}
let output_hash_bytes = sha256::Hash::hash(&buffer);

builder = builder
.push_opcode(OP_TOALTSTACK) // move pre-computed signature minus last byte to alt stack
// .push_opcode(OP_TOALTSTACK) // push the fee-paying scriptpubkey to the alt stack
// .push_opcode(OP_TOALTSTACK) // push the fee amount to the alt stack
// .push_opcode(OP_2DUP) // make a second copy of the vault scriptpubkey and amount so we can check input = output
.push_opcode(OP_TOALTSTACK) // push the first copy of the vault scriptpubkey to the alt stack
.push_opcode(OP_TOALTSTACK) // push the first copy of the vault amount to the alt stack
.push_slice(payout_spk_bytes.as_push_bytes()) // push the payout scriptpubkey
.push_slice(amount.to_le_bytes()) // push the payout amount
.push_opcode(OP_TOALTSTACK) // push the second copy of the vault scriptpubkey to the alt stack
.push_opcode(OP_TOALTSTACK) // push the second copy of the vault amount to the alt stack
// start with encoded leaf hash
.push_opcode(OP_CAT) // encoded leaf hash
.push_opcode(OP_CAT) // encoded leaf hash
.push_opcode(OP_CAT) // input index
.push_opcode(OP_CAT) // spend type
.push_opcode(OP_FROMALTSTACK) // get the output amount
.push_opcode(OP_FROMALTSTACK) // get the second copy of the scriptpubkey
.push_opcode(OP_CAT) // cat the output amount and the second copy of the scriptpubkey
.push_opcode(OP_SHA256) // hash the output
.push_slice(output_hash_bytes.into_32())
.push_opcode(OP_SWAP) // move the hashed encoded outputs below our working sigmsg
.push_opcode(OP_CAT) // outputs
.push_opcode(OP_CAT) // prev sequences
.push_opcode(OP_FROMALTSTACK) // get the other copy of the vault amount
.push_opcode(OP_FROMALTSTACK) // get the other copy of the vault scriptpubkey
// .push_opcode(OP_FROMALTSTACK) // get the fee amount
// .push_opcode(OP_FROMALTSTACK) // get the fee-paying scriptpubkey
// .push_opcode(OP_SWAP) // move the fee-paying scriptpubkey below the fee amount
// .push_opcode(OP_TOALTSTACK) // move fee amount to alt stack
// .push_opcode(OP_CAT) // cat the vault scriptpubkey fee-paying scriptpubkey
.push_opcode(OP_SWAP) // move the vault amount to the top of the stack
.push_opcode(OP_TOALTSTACK) // move the vault amount to the alt stack
.push_opcode(OP_SHA256) // hash the scriptpubkeys, should now be consensus encoding
.push_opcode(OP_SWAP) // move the hashed encoded scriptpubkeys below our working sigmsg
.push_opcode(OP_CAT) // prev scriptpubkeys
.push_opcode(OP_FROMALTSTACK) // get the vault amount
// .push_opcode(OP_FROMALTSTACK) // get the fee amount
// .push_opcode(OP_CAT) // cat the vault amount and the fee amount
.push_opcode(OP_SHA256) // hash the amounts
.push_opcode(OP_SWAP) // move the hashed encoded amounts below our working sigmsg
.push_opcode(OP_CAT) // prev amounts
.push_opcode(OP_CAT) // prevouts
.push_opcode(OP_CAT) // lock time
Expand Down Expand Up @@ -259,3 +226,40 @@ pub(crate) fn add_signature_construction_and_check(builder: Builder) -> Builder
.push_slice(*G_X) // push G again. TODO: DUP this from before and stick it in the alt stack or something
.push_opcode(OP_CHECKSIG)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::utils::{create_address, one_bit_contract_descriptor};
use bitcoin::consensus::serialize;
use bitcoin::Address;
use std::str::FromStr;

#[test]
fn test_cat_create_address() {
let bitcoind_address =
Address::from_str("tb1qe65apqqe3zq7qzaw45zjr4d7fenqdymhr3gums").unwrap();

let contract_address = create_address(bitcoind_address.payload.script_pubkey(), 100_000);
println!("{}", contract_address);

let outpoint = OutPoint::from_str(
"2efc5d63872c24a2f1e2f67b7f89e2ba33e8d218242964e07fbaf210970225b1:1",
)
.unwrap();
let prev_output = TxOut {
script_pubkey: contract_address.payload.script_pubkey(),
value: 100_000,
};
let spending_tx = create_cat_spending_tx(
outpoint,
prev_output,
bitcoind_address.payload.script_pubkey(),
one_bit_contract_descriptor(),
&[],
)
.unwrap();

println!("{}", hex::encode(serialize(&spending_tx).to_vec()));
}
}
8 changes: 4 additions & 4 deletions src/op_ctv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub(crate) fn create_ctv_spending_tx(
output: TxOut,
oracle_attestation: OracleAttestation,
contract_descriptor: ContractDescriptor,
oracle_info: OracleInfo
oracle_info: OracleInfo,
) -> anyhow::Result<Transaction> {
let secp = Secp256k1::new();

Expand Down Expand Up @@ -146,8 +146,8 @@ mod tests {
)
.unwrap();
let attestation = create_dummy_announcement().1;
let spending_tx = create_ctv_spending_tx(outpoint, out, attestation).unwrap();

println!("{}", hex::encode(serialize(&spending_tx).to_vec()));
// let spending_tx = create_ctv_spending_tx(outpoint, out, attestation).unwrap();
//
// println!("{}", hex::encode(serialize(&spending_tx).to_vec()));
}
}
8 changes: 6 additions & 2 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bitcoin::hashes::Hash;
use bitcoin::key::XOnlyPublicKey;
use bitcoin::secp256k1::{Scalar, ThirtyTwoByteHash};
use bitcoin::taproot::TaprootBuilder;
use bitcoin::{Address, Network, ScriptBuf};
use bitcoin::{Address, Network, ScriptBuf, TxOut};
use dlc::secp256k1_zkp::hashes::sha256;
use dlc::secp256k1_zkp::rand::rngs::OsRng;
use dlc::secp256k1_zkp::{KeyPair, Message, Secp256k1, SecretKey};
Expand Down Expand Up @@ -84,7 +84,11 @@ pub fn one_bit_contract_descriptor() -> ContractDescriptor {
}

pub fn create_address(payout_spk: ScriptBuf, amount: u64) -> Address {
let enforce_payout_spk = op_cat_dlc_payout(&payout_spk, amount - 10_000);
let out = TxOut {
script_pubkey: payout_spk,
value: amount - 10_000, // minus 10k sats for fees
};
let enforce_payout_spk = op_cat_dlc_payout(&[out]);

let secp = Secp256k1::new();
let builder = TaprootBuilder::new()
Expand Down