imbibe-domain 0.0.1

holds the types related to Block and Tx used throughrout imbibe
Documentation
use core::{
	fmt::{self, Formatter},
	num::NonZeroU64,
};

use bon::Builder;
use bytes::Bytes;
use cosmrs::{
	Any, Coin,
	tendermint::abci::Code,
	tx::{SignatureBytes, SignerPublicKey},
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};

use super::{Address, NonEmptyBz, Sha256};

#[derive(Debug, Clone, Builder)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Tx<DBZ = Bytes, TBZ = Bytes> {
	block_height: NonZeroU64,
	tx_idx_in_block: u64,
	tx_hash: Sha256,
	msgs: Msgs,
	memo: Option<Memo>,
	timeout_height: Option<NonZeroU64>,
	signatures: Vec<SignatureBytes>,

	#[cfg_attr(
		feature = "serde",
		serde(
			serialize_with = "serialize_signers",
			deserialize_with = "deserialize_signers"
		)
	)]
	signers: Vec<SignerPublicKey>,

	fees: Option<Fees>,
	payer: Address,
	granter: Option<Address>,
	code: Code,
	codespace: Option<Codespace>,
	gas_limit: u64,
	gas_wanted: u64,
	gas_used: u64,
	data_bz: Option<NonEmptyBz<DBZ>>,
	tx_bz: NonEmptyBz<TBZ>,
}

#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Memo(String);

#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Codespace(String);

#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Fees(Vec<Coin>);

#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Msgs(Vec<Any>);

impl Tx {
	pub fn block_height(&self) -> NonZeroU64 {
		self.block_height
	}

	pub fn tx_idx_in_block(&self) -> u64 {
		self.tx_idx_in_block
	}

	pub fn tx_hash(&self) -> &Sha256 {
		&self.tx_hash
	}

	pub fn msgs(&self) -> &Msgs {
		&self.msgs
	}

	pub fn memo(&self) -> Option<&Memo> {
		self.memo.as_ref()
	}

	pub fn timeout_height(&self) -> Option<NonZeroU64> {
		self.timeout_height
	}

	pub fn signatures(&self) -> &[SignatureBytes] {
		&self.signatures
	}

	pub fn signers(&self) -> &[SignerPublicKey] {
		&self.signers
	}

	pub fn fees(&self) -> Option<&Fees> {
		self.fees.as_ref()
	}

	pub fn payer(&self) -> &Address {
		&self.payer
	}

	pub fn granter(&self) -> Option<&Address> {
		self.granter.as_ref()
	}

	pub fn code(&self) -> Code {
		self.code
	}

	pub fn codespace(&self) -> Option<&Codespace> {
		self.codespace.as_ref()
	}

	pub fn gas_limit(&self) -> u64 {
		self.gas_limit
	}

	pub fn gas_wanted(&self) -> u64 {
		self.gas_wanted
	}

	pub fn gas_used(&self) -> u64 {
		self.gas_used
	}

	pub fn data_bz(&self) -> Option<&NonEmptyBz<Bytes>> {
		self.data_bz.as_ref()
	}

	pub fn tx_bz(&self) -> &NonEmptyBz<Bytes> {
		&self.tx_bz
	}
}

impl Memo {
	pub fn new(memo: String) -> Option<Self> {
		(!memo.is_empty()).then_some(memo).map(Self)
	}
}

impl Codespace {
	pub fn new(memo: String) -> Option<Self> {
		(!memo.is_empty()).then_some(memo).map(Self)
	}
}

impl Fees {
	pub fn new(fees: Vec<Coin>) -> Option<Self> {
		(!fees.is_empty()).then_some(Self(fees))
	}

	pub fn get(&self) -> &[Coin] {
		&self.0
	}
}

impl Msgs {
	pub fn new(msgs: Vec<Any>) -> Option<Self> {
		(!msgs.is_empty()).then_some(Self(msgs))
	}

	pub fn get(&self) -> &[Any] {
		&self.0
	}
}

impl AsRef<str> for Memo {
	fn as_ref(&self) -> &str {
		&self.0
	}
}

impl From<Memo> for String {
	fn from(memo: Memo) -> Self {
		memo.0
	}
}

impl AsRef<str> for Codespace {
	fn as_ref(&self) -> &str {
		&self.0
	}
}

impl From<Codespace> for String {
	fn from(codespace: Codespace) -> Self {
		codespace.0
	}
}

impl fmt::Debug for Msgs {
	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
		let msgs: Vec<_> = self
			.0
			.iter()
			.map(|any| {
				format!(
					"Any {{ type_url: \"{}\", value: {:?} }}",
					any.type_url,
					Bytes::copy_from_slice(&any.value)
				)
			})
			.collect();
		f.debug_struct("Msgs").field("msgs", &msgs).finish()
	}
}

#[cfg(feature = "serde")]
fn serialize_signers<S>(signers: &[SignerPublicKey], serializer: S) -> Result<S::Ok, S::Error>
where
	S: Serializer,
{
	signers.iter().cloned().map(Any::from).collect::<Vec<_>>().serialize(serializer)
}

#[cfg(feature = "serde")]
fn deserialize_signers<'de, D>(deserializer: D) -> Result<Vec<SignerPublicKey>, D::Error>
where
	D: Deserializer<'de>,
{
	Vec::<Any>::deserialize(deserializer)?
		.into_iter()
		.map(TryFrom::try_from)
		.collect::<Result<_, _>>()
		.map_err(|e| {
			de::Error::custom(format!("failed to convert Any to SignerPublicKey: {:?}", e))
		})
}