Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -278,10 +278,12 @@ jobs:
path: crates
# We use a synthetic crate to ensure no dev-dependencies are enabled, which can
# be incompatible with some of these targets.
- name: Copy Rust toolchain into the root for use in synthetic crate setup
run: cp crates/rust-toolchain.toml .
- name: Create synthetic crate for testing
run: cargo init --lib ci-build
- name: Copy Rust version into synthetic crate
run: cp crates/rust-toolchain.toml ci-build/
- name: Move Rust toolchain file into synthetic crate
run: mv rust-toolchain.toml ci-build/
- name: Copy patch directives into synthetic crate
run: |
echo "[patch.crates-io]" >> ./ci-build/Cargo.toml
Expand Down Expand Up @@ -315,10 +317,12 @@ jobs:
path: crates
# We use a synthetic crate to ensure no dev-dependencies are enabled, which can
# be incompatible with some of these targets.
- name: Copy Rust toolchain into the root for use in synthetic crate setup
run: cp crates/rust-toolchain.toml .
- name: Create synthetic crate for testing
run: cargo init --lib ci-build
- name: Copy Rust version into synthetic crate
run: cp crates/rust-toolchain.toml ci-build/
- name: Move Rust toolchain file into synthetic crate
run: mv rust-toolchain.toml ci-build/
- name: Copy patch directives into synthetic crate
run: |
echo "[patch.crates-io]" >> ./ci-build/Cargo.toml
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions components/zcash_address/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this library adheres to Rust's notion of

## [Unreleased]

## [0.6.3, 0.7.1] - 2025-05-07
### Added
- `zcash_address::Converter`
- `zcash_address::ZcashAddress::convert_with`

## [0.7.0] - 2025-02-21
### Added
- `zcash_address::unified::Item` to expose the opaque typed encoding of unified
Expand Down
2 changes: 1 addition & 1 deletion components/zcash_address/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "zcash_address"
description = "Zcash address parsing and serialization"
version = "0.7.0"
version = "0.7.1"
authors = [
"Jack Grigg <jack@electriccoin.co>",
]
Expand Down
98 changes: 98 additions & 0 deletions components/zcash_address/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,104 @@ impl<T: TryFromRawAddress> TryFromAddress for (NetworkType, T) {
}
}

/// A trait for converter types that can project from a [`ZcashAddress`] into another type.
///
/// [`ZcashAddress`]: crate::ZcashAddress
///
/// # Examples
///
/// ```
/// use zcash_address::{ConversionError, Converter, UnsupportedAddress, ZcashAddress};
/// use zcash_protocol::consensus::NetworkType;
///
/// struct KeyFinder { }
///
/// impl KeyFinder {
/// fn find_sapling_extfvk(&self, data: [u8; 43]) -> Option<[u8; 73]> {
/// todo!()
/// }
/// }
///
/// // Makes it possible to use a KeyFinder to find the Sapling extfvk that corresponds
/// // to a given ZcashAddress.
/// impl Converter<Option<[u8; 73]>> for KeyFinder {
/// type Error = &'static str;
///
/// fn convert_sapling(
/// &self,
/// net: NetworkType,
/// data: [u8; 43],
/// ) -> Result<Option<[u8; 73]>, ConversionError<Self::Error>> {
/// Ok(self.find_sapling_extfvk(data))
/// }
/// }
/// ```
pub trait Converter<T> {
/// Conversion errors for the user type (e.g. failing to parse the data passed to
/// [`Self::convert_sapling`] as a valid Sapling address).
type Error;

fn convert_sprout(
&self,
net: NetworkType,
data: [u8; 64],
) -> Result<T, ConversionError<Self::Error>> {
let _ = (net, data);
Err(ConversionError::Unsupported(UnsupportedAddress("Sprout")))
}

fn convert_sapling(
&self,
net: NetworkType,
data: [u8; 43],
) -> Result<T, ConversionError<Self::Error>> {
let _ = (net, data);
Err(ConversionError::Unsupported(UnsupportedAddress("Sapling")))
}

fn convert_unified(
&self,
net: NetworkType,
data: unified::Address,
) -> Result<T, ConversionError<Self::Error>> {
let _ = (net, data);
Err(ConversionError::Unsupported(UnsupportedAddress("Unified")))
}

fn convert_transparent_p2pkh(
&self,
net: NetworkType,
data: [u8; 20],
) -> Result<T, ConversionError<Self::Error>> {
let _ = (net, data);
Err(ConversionError::Unsupported(UnsupportedAddress(
"transparent P2PKH",
)))
}

fn convert_transparent_p2sh(
&self,
net: NetworkType,
data: [u8; 20],
) -> Result<T, ConversionError<Self::Error>> {
let _ = (net, data);
Err(ConversionError::Unsupported(UnsupportedAddress(
"transparent P2SH",
)))
}

fn convert_tex(
&self,
net: NetworkType,
data: [u8; 20],
) -> Result<T, ConversionError<Self::Error>> {
let _ = (net, data);
Err(ConversionError::Unsupported(UnsupportedAddress(
"transparent-source restricted P2PKH",
)))
}
}

/// A helper trait for converting another type into a [`ZcashAddress`].
///
/// This trait is sealed and cannot be implemented for types outside this crate. Its
Expand Down
21 changes: 20 additions & 1 deletion components/zcash_address/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ mod kind;
pub mod test_vectors;

pub use convert::{
ConversionError, ToAddress, TryFromAddress, TryFromRawAddress, UnsupportedAddress,
ConversionError, Converter, ToAddress, TryFromAddress, TryFromRawAddress, UnsupportedAddress,
};
pub use encoding::ParseError;
pub use kind::unified;
Expand Down Expand Up @@ -282,6 +282,25 @@ impl ZcashAddress {
}
}

/// Converts this address into another type using the specified converter.
///
/// `convert` can convert into any type `T` for which an implementation of the [`Converter<T>`]
/// trait exists. This enables conversion of [`ZcashAddress`] values into other types to rely
/// on additional context.
pub fn convert_with<T, C: Converter<T>>(
self,
converter: C,
) -> Result<T, ConversionError<C::Error>> {
match self.kind {
AddressKind::Sprout(data) => converter.convert_sprout(self.net, data),
AddressKind::Sapling(data) => converter.convert_sapling(self.net, data),
AddressKind::Unified(data) => converter.convert_unified(self.net, data),
AddressKind::P2pkh(data) => converter.convert_transparent_p2pkh(self.net, data),
AddressKind::P2sh(data) => converter.convert_transparent_p2sh(self.net, data),
AddressKind::Tex(data) => converter.convert_tex(self.net, data),
}
}

/// Returns whether this address has the ability to receive transfers of the given pool type.
pub fn can_receive_as(&self, pool_type: PoolType) -> bool {
use AddressKind::*;
Expand Down
Loading