payto.rs (2346B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2025-2026 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 const SEGMENT: &str = "wallet addr"; 27 28 impl PaytoImpl for BtcWallet { 29 fn as_uri(&self) -> PaytoURI { 30 PaytoURI::from_parts(BITCOIN, format_args!("/{}", self.0)) 31 } 32 33 fn parse(raw: &PaytoURI) -> Result<Self, PaytoErr> { 34 let url = raw.as_ref(); 35 if url.domain() != Some(BITCOIN) { 36 return Err(PaytoErr::UnsupportedKind( 37 BITCOIN, 38 url.domain().unwrap_or_default().into(), 39 )); 40 } 41 let Some(mut segments) = url.path_segments() else { 42 return Err(PaytoErr::MissingSegment(SEGMENT)); 43 }; 44 let Some(first) = segments.next() else { 45 return Err(PaytoErr::MissingSegment(SEGMENT)); 46 }; 47 let address = 48 Address::from_str(first).map_err(|e| PaytoErr::malformed_segment(SEGMENT, e))?; 49 Ok(Self(address.assume_checked())) 50 } 51 } 52 53 impl FromStr for BtcWallet { 54 type Err = bitcoin::address::ParseError; 55 56 fn from_str(s: &str) -> Result<Self, Self::Err> { 57 Ok(Self(Address::from_str(s)?.assume_checked())) 58 } 59 } 60 61 /// Parse a bitcoin payto URI, panic if malformed 62 pub fn btc_payto(url: impl AsRef<str>) -> FullBtcPayto { 63 url.as_ref().parse().expect("invalid btc payto") 64 } 65 66 pub type BtcPayto = Payto<BtcWallet>; 67 pub type FullBtcPayto = FullPayto<BtcWallet>; 68 pub type TransferBtcPayto = TransferPayto<BtcWallet>;