11//! Utility functions for CIP-0134 address.
22
3+ // Ignore URIs that are used in tests and doc-examples.
4+ // cSpell:ignoreRegExp web\+cardano:.+
5+
6+ use std:: fmt:: { Display , Formatter } ;
7+
38use anyhow:: { anyhow, Context , Result } ;
49use pallas:: ledger:: addresses:: Address ;
510
6- /// Parses CIP-0134 URI and returns an address.
7- ///
8- /// # Errors
9- /// - Invalid URI.
11+ /// An URI in the CIP-0134 format.
1012///
11- /// # Examples
13+ /// See the [proposal] for more details.
1214///
13- /// ```
14- /// use pallas::ledger::addresses::{Address, Network};
15- /// use rbac_registration::cardano::cip509::utils::parse_cip0134_uri;
16- ///
17- /// let uri = "web+cardano://addr/stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw";
18- /// let Address::Stake(address) = parse_cip0134_uri(uri).unwrap() else {
19- /// panic!("Unexpected address type");
20- /// };
21- /// assert_eq!(address.network(), Network::Mainnet);
22- /// ```
23- pub fn parse_cip0134_uri ( uri : & str ) -> Result < Address > {
24- let bech32 = uri
25- . strip_prefix ( "web+cardano://addr/" )
26- . ok_or_else ( || anyhow ! ( "Missing schema part of URI" ) ) ?;
27- Address :: from_bech32 ( bech32) . context ( "Unable to parse bech32 part of URI" )
15+ /// [proposal]: https://github.com/cardano-foundation/CIPs/pull/888
16+ #[ derive( Debug ) ]
17+ pub struct Cip0134Uri {
18+ uri : String ,
19+ address : Address ,
20+ }
21+
22+ impl Cip0134Uri {
23+ /// Creates a new `Cip0134Uri` instance by parsing the given URI.
24+ ///
25+ /// # Errors
26+ /// - Invalid URI.
27+ ///
28+ /// # Examples
29+ ///
30+ /// ```
31+ /// use rbac_registration::cardano::cip509::utils::Cip0134Uri;
32+ ///
33+ /// let uri = "web+cardano://addr/stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw";
34+ /// let cip0134_uri = Cip0134Uri::parse(uri).unwrap();
35+ /// ```
36+ pub fn parse ( uri : & str ) -> Result < Self > {
37+ let bech32 = uri
38+ . strip_prefix ( "web+cardano://addr/" )
39+ . ok_or_else ( || anyhow ! ( "Missing schema part of URI" ) ) ?;
40+ let address = Address :: from_bech32 ( bech32) . context ( "Unable to parse bech32 part of URI" ) ?;
41+
42+ Ok ( Self {
43+ uri : uri. to_owned ( ) ,
44+ address,
45+ } )
46+ }
47+
48+ /// Returns a URI string.
49+ ///
50+ /// # Examples
51+ ///
52+ /// ```
53+ /// use rbac_registration::cardano::cip509::utils::Cip0134Uri;
54+ ///
55+ /// let uri = "web+cardano://addr/stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw";
56+ /// let cip0134_uri = Cip0134Uri::parse(uri).unwrap();
57+ /// assert_eq!(cip0134_uri.uri(), uri);
58+ pub fn uri ( & self ) -> & str {
59+ & self . uri
60+ }
61+
62+ /// Returns a URI string.
63+ ///
64+ /// # Examples
65+ ///
66+ /// ```
67+ /// use pallas::ledger::addresses::{Address, Network};
68+ /// use rbac_registration::cardano::cip509::utils::Cip0134Uri;
69+ ///
70+ /// let uri = "web+cardano://addr/stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw";
71+ /// let cip0134_uri = Cip0134Uri::parse(uri).unwrap();
72+ /// let Address::Stake(address) = cip0134_uri.address() else {
73+ /// panic!("Unexpected address type");
74+ /// };
75+ /// assert_eq!(address.network(), Network::Mainnet);
76+ pub fn address ( & self ) -> & Address {
77+ & self . address
78+ }
79+ }
80+
81+ impl Display for Cip0134Uri {
82+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
83+ write ! ( f, "{}" , self . uri( ) )
84+ }
2885}
2986
3087#[ cfg( test) ]
@@ -35,23 +92,25 @@ mod tests {
3592
3693 #[ test]
3794 fn invalid_prefix ( ) {
95+ // cSpell:disable
3896 let test_uris = [
3997 "addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x" ,
4098 "//addr/addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x" ,
4199 "web+cardano:/addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x" ,
42100 "somthing+unexpected://addr/addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x" ,
43101 ] ;
102+ // cSpell:enable
44103
45104 for uri in test_uris {
46- let err = format ! ( "{:?}" , parse_cip0134_uri ( uri) . expect_err( & format!( "{uri}" ) ) ) ;
105+ let err = format ! ( "{:?}" , Cip0134Uri :: parse ( uri) . expect_err( & format!( "{uri}" ) ) ) ;
47106 assert_eq ! ( "Missing schema part of URI" , err) ;
48107 }
49108 }
50109
51110 #[ test]
52111 fn invalid_bech32 ( ) {
53112 let uri = "web+cardano://addr/adr1qx2fxv2umyh" ;
54- let err = format ! ( "{:?}" , parse_cip0134_uri ( uri) . unwrap_err( ) ) ;
113+ let err = format ! ( "{:?}" , Cip0134Uri :: parse ( uri) . unwrap_err( ) ) ;
55114 assert ! ( err. starts_with( "Unable to parse bech32 part of URI" ) ) ;
56115 }
57116
@@ -76,7 +135,8 @@ mod tests {
76135 ] ;
77136
78137 for ( uri, network, payload) in test_data {
79- let Address :: Stake ( address) = parse_cip0134_uri ( uri) . unwrap ( ) else {
138+ let cip0134_uri = Cip0134Uri :: parse ( uri) . expect ( & format ! ( "{uri}" ) ) ;
139+ let Address :: Stake ( address) = cip0134_uri. address else {
80140 panic ! ( "Unexpected address type ({uri})" ) ;
81141 } ;
82142 assert_eq ! ( network, address. network( ) ) ;
@@ -102,10 +162,19 @@ mod tests {
102162 ] ;
103163
104164 for ( uri, network) in test_data {
105- let Address :: Shelley ( address) = parse_cip0134_uri ( uri) . unwrap ( ) else {
165+ let cip0134_uri = Cip0134Uri :: parse ( uri) . expect ( & format ! ( "{uri}" ) ) ;
166+ let Address :: Shelley ( address) = cip0134_uri. address else {
106167 panic ! ( "Unexpected address type ({uri})" ) ;
107168 } ;
108169 assert_eq ! ( network, address. network( ) ) ;
109170 }
110171 }
172+
173+ // The Display should return the original URI.
174+ #[ test]
175+ fn display ( ) {
176+ let uri = "web+cardano://addr/stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw" ;
177+ let cip0134_uri = Cip0134Uri :: parse ( uri) . expect ( & format ! ( "{uri}" ) ) ;
178+ assert_eq ! ( uri, cip0134_uri. to_string( ) ) ;
179+ }
111180}
0 commit comments