payto.rs (2363B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2025 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 use std::str::FromStr; 18 19 use bitcoin::Address; 20 use taler_common::types::payto::{FullPayto, Payto, PaytoErr, PaytoImpl, PaytoURI, TransferPayto}; 21 22 #[derive(Debug, Clone, PartialEq, Eq)] 23 pub struct BtcWallet(pub Address); 24 25 const BITCOIN: &str = "bitcoin"; 26 27 #[derive(Debug, thiserror::Error)] 28 #[error("missing wallet addr in path")] 29 pub struct MissingAddr; 30 31 impl PaytoImpl for BtcWallet { 32 fn as_payto(&self) -> PaytoURI { 33 PaytoURI::from_parts(BITCOIN, format_args!("/{}", self.0)) 34 } 35 36 fn parse(raw: &PaytoURI) -> Result<Self, PaytoErr> { 37 let url = raw.as_ref(); 38 if url.domain() != Some(BITCOIN) { 39 return Err(PaytoErr::UnsupportedKind( 40 BITCOIN, 41 url.domain().unwrap_or_default().to_owned(), 42 )); 43 } 44 let Some(mut segments) = url.path_segments() else { 45 return Err(PaytoErr::custom(MissingAddr)); 46 }; 47 let Some(first) = segments.next() else { 48 return Err(PaytoErr::custom(MissingAddr)); 49 }; 50 let address = Address::from_str(first).map_err(PaytoErr::custom)?; 51 Ok(Self(address.assume_checked())) 52 } 53 } 54 55 impl FromStr for BtcWallet { 56 type Err = bitcoin::address::ParseError; 57 58 fn from_str(s: &str) -> Result<Self, Self::Err> { 59 Ok(Self(Address::from_str(s)?.assume_checked())) 60 } 61 } 62 63 /// Parse a bitcoin payto URI, panic if malformed 64 pub fn btc_payto(url: impl AsRef<str>) -> FullBtcPayto { 65 url.as_ref().parse().expect("invalid btc payto") 66 } 67 68 pub type BtcPayto = Payto<BtcWallet>; 69 pub type FullBtcPayto = FullPayto<BtcWallet>; 70 pub type TransferBtcPayto = TransferPayto<BtcWallet>;