use crate::pset::{
confidential::AssetBlindingFactor,
encode,
raw::ProprietaryKey,
serialize::{Deserialize, Serialize},
Input, Output,
};
pub const PSBT_ELEMENTS_LIQUIDEX_IN_ABF: u8 = 0x00u8;
pub const PSBT_ELEMENTS_LIQUIDEX_OUT_ABF: u8 = 0x00u8;
pub const PSET_LIQUIDEX_PREFIX: &[u8] = b"pset_liquidex";
fn prop_key(keytype: u8) -> ProprietaryKey {
ProprietaryKey {
prefix: PSET_LIQUIDEX_PREFIX.to_vec(),
subtype: keytype,
key: vec![],
}
}
impl Input {
pub fn set_abf(&mut self, abf: AssetBlindingFactor) {
let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_IN_ABF);
self.proprietary.insert(key, abf.serialize());
}
pub fn get_abf(&self) -> Option<Result<AssetBlindingFactor, encode::Error>> {
let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_IN_ABF);
self.proprietary
.get(&key)
.map(|data| AssetBlindingFactor::deserialize(data))
}
}
impl Output {
pub fn set_abf(&mut self, abf: AssetBlindingFactor) {
let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_OUT_ABF);
self.proprietary.insert(key, abf.serialize());
}
pub fn get_abf(&self) -> Option<Result<AssetBlindingFactor, encode::Error>> {
let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_OUT_ABF);
self.proprietary
.get(&key)
.map(|data| AssetBlindingFactor::deserialize(data))
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::AssetId;
use crate::encode::{serialize_hex, Encodable};
use crate::hex::{FromHex, ToHex};
const ELIP0102_IDENTIFIER: &str = "fc0d707365745f6c69717569646578";
#[test]
fn prop_key_serialize() {
let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_IN_ABF);
let mut vec = vec![];
key.consensus_encode(&mut vec).unwrap();
assert_eq!(
vec.to_hex(),
format!("0d{}00", PSET_LIQUIDEX_PREFIX.to_hex())
);
assert!(vec.to_hex().starts_with(&ELIP0102_IDENTIFIER[2..])); }
#[test]
fn set_get_abf() {
let abf_hex = "3311111111111111111111111111111111111111111111111111111111111111";
let abf_bytes = Vec::<u8>::from_hex(abf_hex).unwrap();
let abf = AssetBlindingFactor::from_slice(&abf_bytes).unwrap();
let mut input = Input::default();
assert!(input.get_abf().is_none());
input.set_abf(abf);
assert_eq!(input.get_abf().unwrap().unwrap(), abf);
let input_hex = serialize_hex(&input);
assert!(input_hex.contains(ELIP0102_IDENTIFIER));
assert!(input_hex.contains(abf_hex));
let mut output = Output::default();
assert!(output.get_abf().is_none());
output.set_abf(abf);
assert_eq!(output.get_abf().unwrap().unwrap(), abf);
let output_hex = serialize_hex(&output);
assert!(output_hex.contains(ELIP0102_IDENTIFIER));
assert!(output_hex.contains(abf_hex));
}
#[test]
fn abf_roundtrip() {
use crate::pset::PartiallySignedTransaction;
let abf = AssetBlindingFactor::from_slice(&[3; 32]).unwrap();
let mut pset = PartiallySignedTransaction::new_v2();
let mut input = Input::default();
input.set_abf(abf);
pset.add_input(input);
let mut output = Output {
amount: Some(1),
asset: Some(AssetId::from_slice(&[9; 32]).unwrap()),
..Default::default()
};
output.set_abf(abf);
pset.add_output(output);
let bytes = encode::serialize(&pset);
let pset_back = encode::deserialize::<PartiallySignedTransaction>(&bytes).unwrap();
assert_eq!(pset_back.inputs()[0].get_abf().unwrap().unwrap(), abf);
assert_eq!(pset_back.outputs()[0].get_abf().unwrap().unwrap(), abf);
}
}