1use bitcoin::{
8 address::AddressData,
9 hashes::{hash160::Hash as Hash160, sha256::Hash as Hash256, Hash as _},
10 key::{TapTweak, TweakedPublicKey},
11 script::PushBytes,
12 Address, Network, PubkeyHash, ScriptBuf, ScriptHash, WPubkeyHash, WScriptHash, WitnessProgram,
13 WitnessVersion, XOnlyPublicKey,
14};
15
16use crate::{
17 descriptor::{
18 P2A_PROGRAM_BYTES, P2PKH_LEN, P2SH_LEN, P2TR_LEN, P2TR_TYPE_TAG, P2WPKH_LEN,
19 P2WPKH_P2WSH_TYPE_TAG, P2WSH_LEN,
20 },
21 Descriptor, DescriptorError,
22 DescriptorType::*,
23};
24
25impl Descriptor {
26 pub fn to_address(&self, network: Network) -> Result<Address, DescriptorError> {
28 match self.type_tag() {
29 OpReturn => Err(DescriptorError::InvalidAddressConversion(OpReturn)),
30 P2pkh => {
31 let bytes = self.to_fixed_payload_bytes::<P2PKH_LEN>();
32 let hash = Hash160::from_bytes_ref(&bytes);
33 let address = Address::p2pkh(*hash, network);
34 Ok(address)
35 }
36 P2sh => {
37 let bytes = self.to_fixed_payload_bytes::<P2SH_LEN>();
38 let hash = Hash160::from_bytes_ref(&bytes);
39 let script_hash = ScriptHash::from_raw_hash(*hash);
40 let address = Address::p2sh_from_hash(script_hash, network);
41 Ok(address)
42 }
43 P2wpkh => {
44 let bytes = self.to_fixed_payload_bytes::<P2WPKH_LEN>();
45 let witness_program = WitnessProgram::new(WitnessVersion::V0, &bytes)?;
47 let address = Address::from_witness_program(witness_program, network);
48 Ok(address)
49 }
50 P2wsh => {
51 let bytes = self.to_fixed_payload_bytes::<P2WSH_LEN>();
52 let witness_program = WitnessProgram::new(WitnessVersion::V0, &bytes)?;
54 let address = Address::from_witness_program(witness_program, network);
55 Ok(address)
56 }
57 P2a => {
58 let witness_program = WitnessProgram::p2a();
60 let address = Address::from_witness_program(witness_program, network);
61 Ok(address)
62 }
63 P2tr => {
64 let bytes = self.to_fixed_payload_bytes::<P2TR_LEN>();
65 let xonly_pubkey = XOnlyPublicKey::from_slice(&bytes)?;
67 let address =
72 Address::p2tr_tweaked(xonly_pubkey.dangerous_assume_tweaked(), network);
73 Ok(address)
74 }
75 }
76 }
77
78 pub fn to_script(&self) -> ScriptBuf {
82 let type_tag = self.type_tag();
83 match type_tag {
84 OpReturn => {
85 let payload = self.payload();
86 let push_bytes = <&PushBytes>::try_from(payload)
87 .expect("payload length validated on construction");
88 let script = ScriptBuf::new_op_return(push_bytes);
89 assert!(script.is_op_return());
90 script
91 }
92 P2pkh => {
93 let bytes = self.to_fixed_payload_bytes::<P2PKH_LEN>();
94 let hash = Hash160::from_bytes_ref(&bytes);
95 let pubkey_hash = PubkeyHash::from_raw_hash(*hash);
96 ScriptBuf::new_p2pkh(&pubkey_hash)
97 }
98 P2sh => {
99 let bytes = self.to_fixed_payload_bytes::<P2SH_LEN>();
100 let hash = Hash160::from_bytes_ref(&bytes);
101 let script_hash = ScriptHash::from_raw_hash(*hash);
102 ScriptBuf::new_p2sh(&script_hash)
103 }
104 P2wpkh => {
105 let bytes = self.to_fixed_payload_bytes::<P2WPKH_LEN>();
106 let hash = Hash160::from_bytes_ref(&bytes);
107 let wpubkey_hash = WPubkeyHash::from_raw_hash(*hash);
108 ScriptBuf::new_p2wpkh(&wpubkey_hash)
109 }
110 P2wsh => {
111 let bytes = self.to_fixed_payload_bytes::<P2WSH_LEN>();
112 let hash = Hash256::from_bytes_ref(&bytes);
113 let wscript_hash = WScriptHash::from_raw_hash(*hash);
114 ScriptBuf::new_p2wsh(&wscript_hash)
115 }
116 P2a => ScriptBuf::new_p2a(),
117 P2tr => {
118 let bytes = self.to_fixed_payload_bytes::<P2TR_LEN>();
119 let xonly_pubkey = XOnlyPublicKey::from_slice(&bytes).expect("infallible");
124 ScriptBuf::new_p2tr_tweaked(xonly_pubkey.dangerous_assume_tweaked())
125 }
126 }
127 }
128}
129
130impl TryFrom<Address> for Descriptor {
131 type Error = DescriptorError;
132
133 fn try_from(value: Address) -> Result<Self, Self::Error> {
134 let address_data = value.to_address_data();
135 match address_data {
136 AddressData::P2pkh { pubkey_hash } => Ok(Descriptor::new_p2pkh(
138 &pubkey_hash.as_raw_hash().to_byte_array(),
139 )),
140 AddressData::P2sh { script_hash } => Ok(Descriptor::new_p2sh(
142 &script_hash.as_raw_hash().to_byte_array(),
143 )),
144 AddressData::Segwit { witness_program } => match witness_program.version() {
146 WitnessVersion::V0 => {
147 let payload = witness_program.program().as_bytes();
148 let payload_len = payload.len();
149 match payload_len {
150 20 => {
152 let mut bytes = [0u8; 21];
153 bytes[0] = P2WPKH_P2WSH_TYPE_TAG;
154 bytes[1..].copy_from_slice(payload);
155 Descriptor::from_bytes(&bytes)
156 }
157 32 => {
159 let mut bytes = [0u8; 33];
160 bytes[0] = P2WPKH_P2WSH_TYPE_TAG;
161 bytes[1..].copy_from_slice(payload);
162 Descriptor::from_bytes(&bytes)
163 }
164 _ => Err(DescriptorError::UnsupportedWitnessProgram(format!(
166 "v0 witness program with non-standard length {payload_len} (expected 20 or 32)"
167 ))),
168 }
169 }
170 WitnessVersion::V1 => {
172 let payload = witness_program.program().as_bytes();
173 let payload_len = payload.len();
174 match payload_len {
175 2 if payload == P2A_PROGRAM_BYTES => {
177 let bytes = [P2TR_TYPE_TAG];
178 Descriptor::from_bytes(&bytes)
179 }
180 2 => Err(DescriptorError::UnsupportedWitnessProgram(format!(
182 "v1 witness program with 2 bytes but not P2A (expected [0x4e, 0x73], got [{:#04x}, {:#04x}])",
183 payload[0], payload[1]
184 ))),
185 32 => {
187 let x_only_pk = witness_program.program().as_bytes();
188 let mut bytes = [0u8; 33];
189 bytes[0] = P2TR_TYPE_TAG;
190 bytes[1..].copy_from_slice(x_only_pk);
191 Descriptor::from_bytes(&bytes)
192 }
193 _ => Err(DescriptorError::UnsupportedWitnessProgram(format!(
195 "v1 witness program with non-standard length {payload_len} (expected 2 or 32)"
196 ))),
197 }
198 }
199 _ => Err(DescriptorError::UnsupportedWitnessProgram(format!(
201 "witness version {} is not yet supported",
202 witness_program.version().to_num()
203 ))),
204 },
205 _ => Err(DescriptorError::UnsupportedWitnessProgram(
207 "unknown address type".to_string(),
208 )),
209 }
210 }
211}
212
213impl From<PubkeyHash> for Descriptor {
214 fn from(pubkey_hash: PubkeyHash) -> Self {
215 Descriptor::new_p2pkh(pubkey_hash.as_ref())
216 }
217}
218
219impl From<ScriptHash> for Descriptor {
220 fn from(script_hash: ScriptHash) -> Self {
221 Descriptor::new_p2sh(script_hash.as_ref())
222 }
223}
224
225impl TryFrom<WitnessProgram> for Descriptor {
226 type Error = DescriptorError;
227
228 fn try_from(witness_program: WitnessProgram) -> Result<Self, Self::Error> {
229 let payload: &[u8] = witness_program.program().as_bytes();
230 match witness_program.version() {
231 WitnessVersion::V0 => {
233 let payload_len = payload.len();
234 match payload_len {
235 P2WPKH_LEN => {
237 let mut bytes = [0u8; 21];
238 bytes[0] = P2WPKH_P2WSH_TYPE_TAG;
239 bytes[1..].copy_from_slice(payload);
240 Descriptor::from_bytes(&bytes)
241 }
242 P2WSH_LEN => {
244 let mut bytes = [0u8; 33];
245 bytes[0] = P2WPKH_P2WSH_TYPE_TAG;
246 bytes[1..].copy_from_slice(payload);
247 Descriptor::from_bytes(&bytes)
248 }
249 _ => Err(DescriptorError::UnsupportedWitnessProgram(format!(
251 "v0 witness program with non-standard length {payload_len} (expected 20 or 32)"
252 ))),
253 }
254 }
255 WitnessVersion::V1 => {
257 let payload_len = payload.len();
258 match payload_len {
259 2 if payload == P2A_PROGRAM_BYTES => {
261 let bytes = [P2TR_TYPE_TAG];
262 Descriptor::from_bytes(&bytes)
263 }
264 2 => Err(DescriptorError::UnsupportedWitnessProgram(format!(
266 "v1 witness program with 2 bytes but not P2A (expected [0x4e, 0x73], got [{:#04x}, {:#04x}])",
267 payload[0], payload[1]
268 ))),
269 P2TR_LEN => {
271 let mut bytes = [0u8; 33];
272 bytes[0] = P2TR_TYPE_TAG;
273 bytes[1..].copy_from_slice(payload);
274 Descriptor::from_bytes(&bytes)
275 }
276 _ => Err(DescriptorError::UnsupportedWitnessProgram(format!(
278 "v1 witness program with non-standard length {payload_len} (expected 2 or 32)"
279 ))),
280 }
281 }
282 _ => Err(DescriptorError::UnsupportedWitnessProgram(format!(
284 "witness version {} is not yet supported",
285 witness_program.version().to_num()
286 ))),
287 }
288 }
289}
290
291impl From<XOnlyPublicKey> for Descriptor {
292 fn from(x_only_pubkey: XOnlyPublicKey) -> Self {
293 let payload = x_only_pubkey.serialize();
295 let mut bytes = [0u8; 33];
296 bytes[0] = P2TR_TYPE_TAG;
297 bytes[1..].copy_from_slice(&payload);
298 Descriptor::from_bytes(&bytes).expect("infallible")
299 }
300}
301
302impl From<TweakedPublicKey> for Descriptor {
303 fn from(tweaked_pubkey: TweakedPublicKey) -> Self {
304 let payload = tweaked_pubkey.serialize();
306 let mut bytes = [0u8; 33];
307 bytes[0] = P2TR_TYPE_TAG;
308 bytes[1..].copy_from_slice(&payload);
309 Descriptor::from_bytes(&bytes).expect("infallible")
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use std::str::FromStr;
316
317 use bitcoin::address::NetworkUnchecked;
318
319 use super::*;
320
321 #[cfg(test)]
322 mod proptest_tests {
323 use super::*;
324 use crate::descriptor::{DescriptorType, MAX_OP_RETURN_LEN};
325 use proptest::prelude::*;
326
327 proptest! {
328 #[test]
330 fn op_return_script_property(data in prop::collection::vec(any::<u8>(), 0..=MAX_OP_RETURN_LEN)) {
331 if data.len() <= MAX_OP_RETURN_LEN {
332 let mut bytes = vec![0u8; data.len() + 1];
333 bytes[0] = 0; bytes[1..].copy_from_slice(&data);
335
336 let descriptor = Descriptor::from_bytes(&bytes).expect("valid OP_RETURN should parse");
337 let script = descriptor.to_script();
338 assert!(script.is_op_return());
339 }
340 }
341
342 #[test]
344 fn op_return_address_error_property(data in prop::collection::vec(any::<u8>(), 0..=MAX_OP_RETURN_LEN)) {
345 if data.len() <= MAX_OP_RETURN_LEN {
346 let mut bytes = vec![0u8; data.len() + 1];
347 bytes[0] = 0; bytes[1..].copy_from_slice(&data);
349
350 let descriptor = Descriptor::from_bytes(&bytes).expect("valid OP_RETURN should parse");
351 let address_result = descriptor.to_address(Network::Bitcoin);
352 assert!(address_result.is_err());
353 assert_eq!(
354 address_result.err().unwrap(),
355 DescriptorError::InvalidAddressConversion(DescriptorType::OpReturn)
356 );
357 }
358 }
359 }
360 }
361
362 #[test]
363 fn p2pkh() {
364 let address = "1HnhWpkMHMjgt167kvgcPyurMmsCQ2WPgg";
369 let address = address
370 .parse::<Address<NetworkUnchecked>>()
371 .unwrap()
372 .assume_checked();
373 let desc = Descriptor::try_from(address.clone()).unwrap();
374 assert_eq!(desc.type_tag(), P2pkh);
375
376 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
377 assert_eq!(address, address_translated);
378 }
379
380 #[test]
381 fn p2sh() {
382 let address = "3CK4fEwbMP7heJarmU4eqA3sMbVJyEnU3V";
387 let address = address
388 .parse::<Address<NetworkUnchecked>>()
389 .unwrap()
390 .assume_checked();
391 let desc = Descriptor::try_from(address.clone()).unwrap();
392 assert_eq!(desc.type_tag(), P2sh);
393
394 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
395 assert_eq!(address, address_translated);
396 }
397
398 #[test]
399 fn p2wpkh() {
400 let address = "bc1qvugyzunmnq5y8alrmdrxnsh4gts9p9hmvhyd40";
405 let address = address
406 .parse::<Address<NetworkUnchecked>>()
407 .unwrap()
408 .assume_checked();
409 let desc = Descriptor::try_from(address.clone()).unwrap();
410 assert_eq!(desc.type_tag(), P2wpkh);
411
412 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
413 assert_eq!(address, address_translated);
414 }
415
416 #[test]
417 fn p2wsh() {
418 let address = "bc1qvhu3557twysq2ldn6dut6rmaj3qk04p60h9l79wk4lzgy0ca8mfsnffz65";
423 let address = address
424 .parse::<Address<NetworkUnchecked>>()
425 .unwrap()
426 .assume_checked();
427 let desc = Descriptor::try_from(address.clone()).unwrap();
428 assert_eq!(desc.type_tag(), P2wsh);
429
430 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
431 assert_eq!(address, address_translated);
432 }
433
434 #[test]
435 fn p2a() {
436 let address = "bc1pfeessrawgf";
441 let address = address
442 .parse::<Address<NetworkUnchecked>>()
443 .unwrap()
444 .assume_checked();
445 let desc = Descriptor::try_from(address.clone()).unwrap();
446 assert_eq!(desc.type_tag(), P2a);
447
448 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
449 assert_eq!(address, address_translated);
450 }
451
452 #[test]
453 fn p2tr() {
454 let address = "bc1ppuxgmd6n4j73wdp688p08a8rte97dkn5n70r2ym6kgsw0v3c5ensrytduf";
459 let address = address
460 .parse::<Address<NetworkUnchecked>>()
461 .unwrap()
462 .assume_checked();
463 let desc = Descriptor::try_from(address.clone()).unwrap();
464 assert_eq!(desc.type_tag(), P2tr);
465
466 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
467 assert_eq!(address, address_translated);
468 }
469
470 #[test]
471 fn op_return_script() {
472 let s = "00636861726c6579206c6f766573206865696469";
477 let desc = Descriptor::from_str(s).unwrap();
478
479 let script = desc.to_script();
480 assert!(script.is_op_return());
481 assert!(script.len() < 83);
484 }
485
486 #[test]
487 fn op_return_script_large() {
488 use bitcoin::{opcodes::all::OP_RETURN, script::Instruction};
495 for len in [75, 76, 255, 256, 65535, 65536] {
496 let data = vec![0xff; len];
497 let desc = Descriptor::new_op_return(&data).unwrap();
498
499 let script = desc.to_script();
500 assert!(script.is_op_return());
501 let mut iter = script.instructions();
502 assert_eq!(iter.next(), Some(Ok(Instruction::Op(OP_RETURN))));
503 assert!(
504 matches!(iter.next(), Some(Ok(Instruction::PushBytes(x))) if x.as_bytes() == data)
505 );
506 assert_eq!(iter.next(), None);
507 }
508 }
509
510 #[test]
511 fn op_return_push_bytes_conversion() {
512 use bitcoin::{opcodes::all::OP_RETURN, script::Instruction};
515 for len in [0, 1, 75, 76, 255, 256, 65535, 65536] {
516 let data = vec![0xab; len];
517
518 let push_bytes =
520 <&PushBytes>::try_from(data.as_slice()).expect("should convert to PushBytes");
521
522 let script = ScriptBuf::new_op_return(push_bytes);
524 assert!(script.is_op_return());
525
526 let mut iter = script.instructions();
528 assert_eq!(iter.next(), Some(Ok(Instruction::Op(OP_RETURN))));
529 assert!(
530 matches!(iter.next(), Some(Ok(Instruction::PushBytes(x))) if x.as_bytes() == data)
531 );
532 assert_eq!(iter.next(), None);
533 }
534 }
535
536 #[test]
537 fn p2pkh_script() {
538 let s = "01b8268ce4d481413c4e848ff353cd16104291c45b";
543 let desc = Descriptor::from_str(s).unwrap();
544
545 let script = desc.to_script();
546 assert!(script.is_p2pkh())
547 }
548
549 #[test]
550 fn p2sh_script() {
551 let s = "02748284390f9e263a4b766a75d0633c50426eb875";
556 let desc = Descriptor::from_str(s).unwrap();
557
558 let script = desc.to_script();
559 assert!(script.is_p2sh())
560 }
561
562 #[test]
563 fn p2wpkh_script() {
564 let s = "03671041727b982843f7e3db4669c2f542e05096fb";
569 let desc = Descriptor::from_str(s).unwrap();
570
571 let script = desc.to_script();
572 assert!(script.is_p2wpkh())
573 }
574
575 #[test]
576 fn p2wsh_script() {
577 let s = "0365f91a53cb7120057db3d378bd0f7d944167d43a7dcbff15d6afc4823f1d3ed3";
582 let desc = Descriptor::from_str(s).unwrap();
583
584 let script = desc.to_script();
585 assert!(script.is_p2wsh())
586 }
587
588 #[test]
589 fn p2a_script() {
590 let s = "04";
595 let desc = Descriptor::from_str(s).unwrap();
596
597 let script = desc.to_script();
598 assert_eq!(script.len(), 4);
599 assert_eq!(script.as_bytes(), &[0x51, 0x02, 0x4e, 0x73]);
600
601 let witness_program = WitnessProgram::new(WitnessVersion::V1, &P2A_PROGRAM_BYTES).unwrap();
603 assert!(witness_program.is_p2a());
604 assert_eq!(witness_program.program().as_bytes(), P2A_PROGRAM_BYTES);
605 }
606
607 #[test]
608 fn p2tr_script() {
609 let s = "040f0c8db753acbd17343a39c2f3f4e35e4be6da749f9e35137ab220e7b238a667";
614 let desc = Descriptor::from_str(s).unwrap();
615
616 let script = desc.to_script();
617 assert!(script.is_p2tr())
618 }
619
620 #[test]
621 fn from_pubkey_hash() {
622 let hash = "b8268ce4d481413c4e848ff353cd16104291c45b";
627 let hash = hash.parse::<PubkeyHash>().unwrap();
628 let desc = Descriptor::from(hash);
629 assert_eq!(desc.type_tag(), P2pkh);
630
631 let address = Address::p2pkh(hash, Network::Bitcoin);
632 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
633 assert_eq!(address, address_translated);
634 }
635
636 #[test]
637 fn from_script_hash() {
638 let hash = "748284390f9e263a4b766a75d0633c50426eb875";
643 let hash = hash.parse::<ScriptHash>().unwrap();
644 let desc = Descriptor::from(hash);
645 assert_eq!(desc.type_tag(), P2sh);
646
647 let address = Address::p2sh_from_hash(hash, Network::Bitcoin);
648 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
649 assert_eq!(address, address_translated);
650 }
651
652 #[test]
653 fn from_witness_program() {
654 let address = "bc1qvugyzunmnq5y8alrmdrxnsh4gts9p9hmvhyd40";
659 let address = address
660 .parse::<Address<NetworkUnchecked>>()
661 .unwrap()
662 .assume_checked();
663 let witness_program = address.witness_program().unwrap();
664 let desc = Descriptor::try_from(witness_program).unwrap();
665 assert_eq!(desc.type_tag(), P2wpkh);
666
667 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
668 assert_eq!(address, address_translated);
669
670 let address = "bc1qvhu3557twysq2ldn6dut6rmaj3qk04p60h9l79wk4lzgy0ca8mfsnffz65";
675 let address = address
676 .parse::<Address<NetworkUnchecked>>()
677 .unwrap()
678 .assume_checked();
679 let witness_program = address.witness_program().unwrap();
680 let desc = Descriptor::try_from(witness_program).unwrap();
681 assert_eq!(desc.type_tag(), P2wsh);
682
683 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
684 assert_eq!(address, address_translated);
685
686 let address = "bc1pfeessrawgf";
691 let address = address
692 .parse::<Address<NetworkUnchecked>>()
693 .unwrap()
694 .assume_checked();
695 let witness_program = address.witness_program().unwrap();
696 let desc = Descriptor::try_from(witness_program).unwrap();
697 assert_eq!(desc.type_tag(), P2a);
698
699 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
700 assert_eq!(address, address_translated);
701
702 let address = "bc1ppuxgmd6n4j73wdp688p08a8rte97dkn5n70r2ym6kgsw0v3c5ensrytduf";
707 let address = address
708 .parse::<Address<NetworkUnchecked>>()
709 .unwrap()
710 .assume_checked();
711 let witness_program = address.witness_program().unwrap();
712 let desc = Descriptor::try_from(witness_program).unwrap();
713 assert_eq!(desc.type_tag(), P2tr);
714
715 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
716 assert_eq!(address, address_translated);
717 }
718
719 #[test]
720 fn xonly_pubkey() {
721 let xonly_pk = "0f0c8db753acbd17343a39c2f3f4e35e4be6da749f9e35137ab220e7b238a667";
726 let xonly_pk = xonly_pk.parse::<XOnlyPublicKey>().unwrap();
727 let desc = Descriptor::from(xonly_pk);
728 assert_eq!(desc.type_tag(), P2tr);
729
730 let address = "bc1ppuxgmd6n4j73wdp688p08a8rte97dkn5n70r2ym6kgsw0v3c5ensrytduf";
731 let address = address
732 .parse::<Address<NetworkUnchecked>>()
733 .unwrap()
734 .assume_checked();
735 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
736 assert_eq!(address, address_translated);
737 }
738
739 #[test]
740 fn tweaked_pubkey() {
741 let xonly_pk = "0f0c8db753acbd17343a39c2f3f4e35e4be6da749f9e35137ab220e7b238a667";
746 let xonly_pk = xonly_pk.parse::<XOnlyPublicKey>().unwrap();
747 let tweaked_pk = xonly_pk.dangerous_assume_tweaked();
748 let desc = Descriptor::from(tweaked_pk);
749 assert_eq!(desc.type_tag(), P2tr);
750
751 let address = "bc1ppuxgmd6n4j73wdp688p08a8rte97dkn5n70r2ym6kgsw0v3c5ensrytduf";
752 let address = address
753 .parse::<Address<NetworkUnchecked>>()
754 .unwrap()
755 .assume_checked();
756 let address_translated = desc.to_address(Network::Bitcoin).unwrap();
757 assert_eq!(address, address_translated);
758 }
759}