diff --git a/Cargo.toml b/Cargo.toml index 57daac63..f24d4482 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,6 @@ members = [ "bindings/tbdex_uniffi", "crates/tbdex", - "crates/protocol", ] default-members = [ "crates/tbdex", diff --git a/crates/protocol/Cargo.toml b/crates/protocol/Cargo.toml deleted file mode 100644 index e3b394fa..00000000 --- a/crates/protocol/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "protocol" -version = "0.1.0" -edition = "2021" -homepage.workspace = true -repository.workspace = true -license-file.workspace = true - -[dependencies] -chrono = { version = "0.4.31", features = ["serde"] } -credentials = { git = "https://github.com/TBD54566975/web5-rs", rev = "694db64b72a92e17880c87d31a4bf11fe3bb8793"} -jsonschema = "0.17.1" -serde = { version = "1.0.193", features = ["derive"] } -serde_json = "1.0.108" -type-safe-id = { version = "0.2.1", features = ["serde"] } -thiserror = "1.0.50" -serde_with = "3.4.0" \ No newline at end of file diff --git a/crates/protocol/src/lib.rs b/crates/protocol/src/lib.rs deleted file mode 100644 index 019d6536..00000000 --- a/crates/protocol/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod messages; -pub mod resources; - -#[cfg(test)] -pub mod test_data; diff --git a/crates/protocol/src/messages/close.rs b/crates/protocol/src/messages/close.rs deleted file mode 100644 index d1494e61..00000000 --- a/crates/protocol/src/messages/close.rs +++ /dev/null @@ -1,83 +0,0 @@ -use ::serde::{Deserialize, Serialize}; -use chrono::Utc; -use serde_with::skip_serializing_none; -use type_safe_id::{DynamicType, TypeSafeId}; - -use super::{Message, MessageError, MessageKind, MessageMetadata}; - -pub struct Close; - -impl Close { - pub fn create( - from: String, - to: String, - exchange_id: TypeSafeId, - reason: Option, - ) -> Result, MessageError> { - let metadata = MessageMetadata { - from, - to, - kind: MessageKind::Close, - id: MessageKind::Close.typesafe_id()?, - exchange_id, - created_at: Utc::now(), - }; - - let data = CloseData { reason }; - - Ok(Message { - metadata, - data, - signature: None, - }) - } -} - -/// A struct representing the data contained within the [`Message`] for a [`Close`]. -/// -/// See [Quote](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#close) for more -/// information. -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[skip_serializing_none] -#[serde(rename_all = "camelCase")] -pub struct CloseData { - /// an explanation of why the exchange is being closed/completed - reason: Option, -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::test_data::TestData; - - #[test] - fn can_create() { - let close = Close::create( - "did:example:from_1234".to_string(), - "did:example:to_1234".to_string(), - MessageKind::Rfq.typesafe_id().unwrap(), - Some("I don't want to do business with you any more".to_string()), - ) - .expect("failed to create Close"); - - assert_eq!( - close.data.reason, - Some("I don't want to do business with you any more".to_string()) - ); - assert_eq!(close.metadata.id.type_prefix(), "close"); - } - - #[test] - fn can_parse_close_from_json() { - let close = TestData::get_close( - "did:example:from_1234".to_string(), - MessageKind::Rfq - .typesafe_id() - .expect("failed to generate exchange_id"), - ); - let json = serde_json::to_string(&close).expect("failed to serialize Close"); - let parsed_close: Message = - serde_json::from_str(&json).expect("failed to deserialize Close"); - assert_eq!(close, parsed_close); - } -} diff --git a/crates/protocol/src/messages/mod.rs b/crates/protocol/src/messages/mod.rs deleted file mode 100644 index 65d125d5..00000000 --- a/crates/protocol/src/messages/mod.rs +++ /dev/null @@ -1,89 +0,0 @@ -pub mod close; -pub mod order; -pub mod order_status; -pub mod quote; - -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use serde_json::to_string; -use type_safe_id::{DynamicType, TypeSafeId}; - -/// An enum representing all possible [`Message`] kinds. -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "lowercase")] -pub enum MessageKind { - Close, - Order, - OrderStatus, - Quote, - Rfq, -} - -/// A struct representing the metadata present on every [`Message`]. -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct MessageMetadata { - /// The message's ID - pub id: TypeSafeId, - /// This defines the data property's type (e.g. rfq, quote etc.) - pub kind: MessageKind, - /// ID for a "exchange" of messages between Alice <-> PFI. - /// Set by the first message in an exchange. - pub exchange_id: TypeSafeId, - /// The sender's DID - pub from: String, - /// The recipient's DID - pub to: String, - /// ISO 8601 - pub created_at: DateTime, -} - -/// A struct representing the structure and common functionality available to all Messages. -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Message { - /// An object containing fields about the message - pub metadata: MessageMetadata, - /// The actual message content - pub data: T, - /// The signature that verifies the authenticity and integrity of the message - pub signature: Option, -} - -/// Errors that can occur when working with [`Message`]s. -#[derive(thiserror::Error, Debug)] -pub enum MessageError { - #[error(transparent)] - SerdeJsonError(#[from] serde_json::Error), - #[error(transparent)] - TypeSafeIdError(#[from] type_safe_id::Error), -} - -impl MessageKind { - /// Returns the [`TypeSafeId`] of the [`MessageKind`]. - pub fn typesafe_id(&self) -> Result, MessageError> { - let serialized_kind = to_string(&self)?; - let dynamic_type = DynamicType::new(serialized_kind.trim_matches('"'))?; - Ok(TypeSafeId::new_with_type(dynamic_type)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn message_kind_typesafe_id() { - let close_id = MessageKind::Close.typesafe_id().unwrap(); - let order_id = MessageKind::Order.typesafe_id().unwrap(); - let order_status_id = MessageKind::OrderStatus.typesafe_id().unwrap(); - let quote_id = MessageKind::Quote.typesafe_id().unwrap(); - let rfq_id = MessageKind::Rfq.typesafe_id().unwrap(); - - assert!(close_id.to_string().starts_with("close_")); - assert!(order_id.to_string().starts_with("order_")); - assert!(order_status_id.to_string().starts_with("orderstatus_")); - assert!(quote_id.to_string().starts_with("quote_")); - assert!(rfq_id.to_string().starts_with("rfq_")); - } -} diff --git a/crates/protocol/src/messages/order.rs b/crates/protocol/src/messages/order.rs deleted file mode 100644 index 40c59c02..00000000 --- a/crates/protocol/src/messages/order.rs +++ /dev/null @@ -1,72 +0,0 @@ -use ::serde::{Deserialize, Serialize}; -use chrono::Utc; -use type_safe_id::{DynamicType, TypeSafeId}; - -use super::{Message, MessageError, MessageKind, MessageMetadata}; - -pub struct Order; - -impl Order { - pub fn create( - from: String, - to: String, - exchange_id: TypeSafeId, - ) -> Result, MessageError> { - let metadata = MessageMetadata { - from, - to, - kind: MessageKind::Order, - id: MessageKind::Order.typesafe_id()?, - exchange_id, - created_at: Utc::now(), - }; - - let data = OrderData; - - Ok(Message { - metadata, - data, - signature: None, - }) - } -} - -/// A struct representing the data contained within the [`Message`] for an [`Order`]. -/// Currently, [`Order`] contains no data fields. -/// -/// See [Order](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#order) for more -/// information. -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct OrderData; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn can_create() { - let order = Order::create( - "did:example:from_1234".to_string(), - "did:example:to_1234".to_string(), - MessageKind::Rfq.typesafe_id().unwrap(), - ) - .expect("failed to create Order"); - - assert_eq!(order.metadata.id.type_prefix(), "order"); - } - - #[test] - fn can_parse_order_from_json() { - let order = Order::create( - "did:example:from_1234".to_string(), - "did:example:to_1234".to_string(), - MessageKind::Rfq.typesafe_id().unwrap(), - ) - .expect("Could not create Order"); - let json: String = serde_json::to_string(&order).expect("failed to serialize Order"); - let parsed_order: Message = - serde_json::from_str(&json).expect("failed to deserialize Order"); - assert_eq!(order, parsed_order); - } -} diff --git a/crates/protocol/src/messages/order_status.rs b/crates/protocol/src/messages/order_status.rs deleted file mode 100644 index ac49888b..00000000 --- a/crates/protocol/src/messages/order_status.rs +++ /dev/null @@ -1,79 +0,0 @@ -use ::serde::{Deserialize, Serialize}; -use chrono::Utc; -use type_safe_id::{DynamicType, TypeSafeId}; - -use super::{Message, MessageError, MessageKind, MessageMetadata}; - -pub struct OrderStatus; - -impl OrderStatus { - pub fn create( - from: String, - to: String, - exchange_id: TypeSafeId, - order_status: String, - ) -> Result, MessageError> { - let metadata = MessageMetadata { - from, - to, - kind: MessageKind::OrderStatus, - id: MessageKind::OrderStatus.typesafe_id()?, - exchange_id, - created_at: Utc::now(), - }; - - let data = OrderStatusData { order_status }; - - Ok(Message { - metadata, - data, - signature: None, - }) - } -} - -/// A struct representing the data contained within the [`Message`] for an [`OrderStatus`]. -/// Currently, [`OrderStatus`] contains no data fields. -/// -/// See [OrderStatus](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#orderstatus) for more -/// information. -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct OrderStatusData { - /// Current status of Order that's being executed - order_status: String, -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn can_create() { - let order_status: Message = OrderStatus::create( - "did:example:from_1234".to_string(), - "did:example:to_1234".to_string(), - MessageKind::Rfq.typesafe_id().unwrap(), - "COMPLETED".to_string(), - ) - .expect("failed to create OrderStatus"); - - assert_eq!(order_status.metadata.id.type_prefix(), "orderstatus"); - } - - #[test] - fn can_parse_order_status_from_json() { - let order_status = OrderStatus::create( - "did:example:from_1234".to_string(), - "did:example:to_1234".to_string(), - MessageKind::Rfq.typesafe_id().unwrap(), - "COMPLETED".to_string(), - ) - .expect("Could not create OrderStatus"); - let json: String = - serde_json::to_string(&order_status).expect("failed to serialize OrderStatus"); - let parsed_order_status: Message = - serde_json::from_str(&json).expect("failed to deserialize OrderStatus"); - assert_eq!(order_status, parsed_order_status); - } -} diff --git a/crates/protocol/src/messages/quote.rs b/crates/protocol/src/messages/quote.rs deleted file mode 100644 index 6cbaa00c..00000000 --- a/crates/protocol/src/messages/quote.rs +++ /dev/null @@ -1,139 +0,0 @@ -use ::serde::{Deserialize, Serialize}; -use chrono::{DateTime, Utc}; -use serde_with::skip_serializing_none; -use type_safe_id::{DynamicType, TypeSafeId}; - -use super::{Message, MessageError, MessageKind, MessageMetadata}; - -pub struct Quote; - -impl Quote { - pub fn create( - from: String, - to: String, - exchange_id: TypeSafeId, - data: QuoteData, - ) -> Result, MessageError> { - let metadata = MessageMetadata { - from, - to, - kind: MessageKind::Quote, - id: MessageKind::Quote.typesafe_id()?, - exchange_id, - created_at: Utc::now(), - }; - - Ok(Message { - metadata, - data, - signature: None, - }) - } -} - -/// A struct representing the data contained within the [`Message`] for a [`Quote`]. -/// -/// See [Quote](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#quote) for more -/// information. -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[skip_serializing_none] -#[serde(rename_all = "camelCase")] -pub struct QuoteData { - /// When this quote expires. Expressed as ISO8601 - pub expires_at: DateTime, - /// the amount of payin currency that the PFI will receive - pub payin: QuoteDetails, - /// the amount of payout currency that Alice will receive - pub payout: QuoteDetails, - /// Object that describes how to pay the PFI, and how to get paid by the PFI (e.g. BTC address, payment link) - pub payment_instructions: Option, -} - -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[skip_serializing_none] -#[serde(rename_all = "camelCase")] -pub struct QuoteDetails { - /// ISO 3166 currency code string - pub currency_code: String, - /// The amount of currency expressed in the smallest respective unit - pub amount_subunits: String, - /// The amount paid in fees expressed in the smallest respectice unit - pub fee_subunits: Option, -} - -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[skip_serializing_none] -#[serde(rename_all = "camelCase")] -pub struct PaymentInstructions { - /// Link or Instruction describing how to pay the PFI. - pub payin: Option, - /// Link or Instruction describing how to get paid by the PFI - pub payout: Option, -} - -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[skip_serializing_none] -#[serde(rename_all = "camelCase")] -pub struct PaymentInstruction { - /// Link or Instruction describing how to pay the PFI. - pub link: Option, - /// Instruction on how Alice can pay PFI, or how Alice can be paid by the PFI - pub instruction: Option, -} - -#[cfg(test)] -mod tests { - use crate::test_data::TestData; - - use super::*; - - #[test] - fn can_create() { - let quote = Quote::create( - "did:example:from_1234".to_string(), - "did:example:to_1234".to_string(), - MessageKind::Rfq.typesafe_id().unwrap(), - QuoteData { - expires_at: Utc::now(), - payin: QuoteDetails { - currency_code: "USD".to_string(), - amount_subunits: "100".to_string(), - fee_subunits: Some("10".to_string()), - }, - payout: QuoteDetails { - currency_code: "BTC".to_string(), - amount_subunits: "2500".to_string(), - fee_subunits: None, - }, - payment_instructions: Some(PaymentInstructions { - payin: Some(PaymentInstruction { - link: Some("example.com/payin".to_string()), - instruction: Some("Hand me the cash".to_string()), - }), - payout: Some(PaymentInstruction { - link: None, - instruction: Some("BOLT 12".to_string()), - }), - }), - }, - ) - .expect("failed to create Quote"); - - assert_eq!(quote.metadata.id.type_prefix(), "quote"); - } - - #[test] - fn can_parse_quote_from_json() { - let quote = TestData::get_quote( - "did:example:from_1234".to_string(), - "did:example:to_1234".to_string(), - MessageKind::Rfq - .typesafe_id() - .expect("failed to generate exchange_id"), - ); - let json = serde_json::to_string("e).expect("failed to serialize Quote"); - let parsed_quote: Message = - serde_json::from_str(&json).expect("failed to deserialize Quote"); - assert_eq!(quote, parsed_quote); - } -} diff --git a/crates/protocol/src/resources/mod.rs b/crates/protocol/src/resources/mod.rs deleted file mode 100644 index 158bb676..00000000 --- a/crates/protocol/src/resources/mod.rs +++ /dev/null @@ -1,73 +0,0 @@ -pub mod offering; - -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use serde_json::to_string; -use type_safe_id::{DynamicType, TypeSafeId}; - -/// An enum representing all possible [`Resource`] kinds. -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "lowercase")] -pub enum ResourceKind { - Offering, -} - -/// A struct representing the metadata present on every [`Resource`]. -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ResourceMetadata { - /// The resource's ID - pub id: TypeSafeId, - /// This defines the data property's type (e.g. offering) - pub kind: ResourceKind, - /// The author's DID - pub from: String, - /// ISO 8601 timestamp - pub created_at: DateTime, - /// ISO 8601 timestamp - pub updated_at: Option>, - /// Version of the protocol in use (x.x format). The protocol version must remain consistent across messages in a given exchange. Messages sharing the same exchangeId MUST also have the same protocol version. - pub protocol: String, -} - -/// A struct representing the structure and common functionality available to all Resources. -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Resource { - /// An object containing fields about the Resource - pub metadata: ResourceMetadata, - /// The actual Resource content - pub data: T, - /// The signature that verifies the authenticity and integrity of the Resource - pub signature: String, -} - -/// Errors that can occur when working with [`Resource`]s. -#[derive(thiserror::Error, Debug)] -pub enum ResourceError { - #[error(transparent)] - SerdeJsonError(#[from] serde_json::Error), - #[error(transparent)] - TypeSafeIdError(#[from] type_safe_id::Error), -} - -impl ResourceKind { - /// Returns the [`TypeSafeId`] of the [`ResourceKind`]. - pub fn typesafe_id(&self) -> Result, ResourceError> { - let serialized_kind = to_string(&self)?; - let dynamic_type = DynamicType::new(serialized_kind.trim_matches('"'))?; - Ok(TypeSafeId::new_with_type(dynamic_type)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn resource_kind_typesafe_id() { - let offering_id = ResourceKind::Offering.typesafe_id().unwrap(); - - assert!(offering_id.to_string().starts_with("offering_")); - } -} diff --git a/crates/protocol/src/resources/offering.rs b/crates/protocol/src/resources/offering.rs deleted file mode 100644 index 9f24e961..00000000 --- a/crates/protocol/src/resources/offering.rs +++ /dev/null @@ -1,177 +0,0 @@ -use crate::resources::{Resource, ResourceError, ResourceKind, ResourceMetadata}; -use chrono::Utc; -use credentials::pex::v2::PresentationDefinition; -use serde::{Deserialize, Serialize}; -use serde_json::Value as JsonValue; - -/// Struct that interacts with an [`Offering`] [`Resource`] -pub struct Offering; - -/// Struct for passing parameters to [`Offering::create`] -#[derive(Debug, Default)] -pub struct CreateOptions { - pub from: String, - pub protocol: Option, - pub data: OfferingData, -} - -impl Offering { - pub fn create(options: CreateOptions) -> Result, ResourceError> { - let metadata = ResourceMetadata { - id: ResourceKind::Offering.typesafe_id()?, - kind: ResourceKind::Offering, - from: options.from, - created_at: Utc::now(), - updated_at: Some(Utc::now()), - protocol: match options.protocol { - Some(p) => p, - None => "1.0".to_string(), - }, - }; - - // todo implement signing https://github.com/TBD54566975/tbdex-rs/issues/27 - let signature = "todo a valid signature".to_string(); - - Ok(Resource { - metadata, - data: options.data, - signature, - }) - } -} - -/// Struct the data contained within the [`Resource`] for an [`Offering`]. -/// -/// See [Offering](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#offering) for more -/// information. -#[derive(Debug, Deserialize, PartialEq, Serialize, Default)] -#[serde(rename_all = "camelCase")] -pub struct OfferingData { - /// Brief description of what is being offered. - pub description: String, - /// Number of payout units Alice would get for 1 payin unit - pub payout_units_per_payin_unit: String, - /// Details and options associated to the payin currency - pub payin: PayinDetails, - /// Details and options associated to the payout currency - pub payout: PayoutDetails, - /// Claim(s) required when submitting an RFQ for this offering. - pub required_claims: PresentationDefinition, -} - -/// Struct for [Offering's PayinDetails](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#payindetails) -#[derive(Debug, Deserialize, PartialEq, Serialize, Default)] -#[serde(rename_all = "camelCase")] -pub struct PayinDetails { - /// ISO 4217 currency code string - pub currency_code: String, - /// Minimum amount of currency that the offer is valid for - pub min: Option, - /// Maximum amount of currency that the offer is valid for - pub max: Option, - /// A list of payment methods to select from - pub methods: Vec, -} - -/// Struct for [Offering's PayinMethod](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#payinmethod) -#[derive(Debug, Deserialize, PartialEq, Serialize, Default)] -#[serde(rename_all = "camelCase")] -pub struct PayinMethod { - /// Unique string identifying a single kind of payment method i.e. (i.e. DEBIT_CARD, BITCOIN_ADDRESS, SQUARE_PAY) - pub kind: String, - /// Payment Method name. Expected to be rendered on screen. - pub name: Option, - /// Blurb containing helpful information about the payment method. Expected to be rendered on screen. e.g. "segwit addresses only" - pub description: Option, - /// The category for which the given method belongs to - pub group: Option, - /// A JSON Schema containing the fields that need to be collected in the RFQ's selected payment methods in order to use this payment method. - pub required_payment_details: Option, - /// Fee charged to use this payment method. absence of this field implies that there is no additional fee associated to the respective payment method - pub fee: Option, - /// Minimum amount required to use this payment method. - pub min: Option, - /// Maximum amount allowed when using this payment method. - pub max: Option, -} - -/// Struct for [Offering's PayoutDetails](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#payoutdetails) -#[derive(Debug, Deserialize, PartialEq, Serialize, Default)] -#[serde(rename_all = "camelCase")] -pub struct PayoutDetails { - /// ISO 4217 currency code string - pub currency_code: String, - /// Minimum amount of currency that the offer is valid for - pub min: Option, - /// Maximum amount of currency that the offer is valid for - pub max: Option, - /// A list of payment methods to select from - pub methods: Vec, -} - -/// Struct for [Offering's PayinMethod](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#payinmethod) -#[derive(Debug, Deserialize, PartialEq, Serialize, Default)] -#[serde(rename_all = "camelCase")] -pub struct PayoutMethod { - /// Unique string identifying a single kind of payment method i.e. (i.e. DEBIT_CARD, BITCOIN_ADDRESS, SQUARE_PAY) - pub kind: String, - /// Estimated time taken to settle an order, expressed in seconds - pub estimated_settlement_time: u64, - /// Payment Method name. Expected to be rendered on screen. - pub name: Option, - /// Blurb containing helpful information about the payment method. Expected to be rendered on screen. e.g. "segwit addresses only" - pub description: Option, - /// The category for which the given method belongs to - pub group: Option, - /// A JSON Schema containing the fields that need to be collected in the RFQ's selected payment methods in order to use this payment method. - pub required_payment_details: Option, - /// Fee charged to use this payment method. absence of this field implies that there is no additional fee associated to the respective payment method - pub fee: Option, - /// Minimum amount required to use this payment method. - pub min: Option, - /// Maximum amount allowed when using this payment method. - pub max: Option, -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::test_data::TestData; - - #[test] - fn can_create() { - let offering = Offering::create(CreateOptions { - from: "did:example:1234".to_string(), - data: OfferingData { - description: "my fake offering".to_string(), - payout_units_per_payin_unit: "2".to_string(), - payin: PayinDetails { - currency_code: "USD".to_string(), - ..Default::default() - }, - payout: PayoutDetails { - currency_code: "BTC".to_string(), - ..Default::default() - }, - required_claims: PresentationDefinition::default(), - }, - ..Default::default() - }) - .expect("failed to create offering"); - - assert_eq!(offering.metadata.id.type_prefix(), "offering"); - assert_eq!(offering.metadata.from, "did:example:1234".to_string()); - assert_eq!(offering.metadata.protocol, "1.0".to_string()); - assert_eq!(offering.data.description, "my fake offering"); - } - - #[test] - fn can_parse_offering_from_json() { - let offering = TestData::get_offering("did:example:1234".to_string()); - let json = serde_json::to_string(&offering).expect("failed to serialize offering"); - let parsed_offering: Resource = - serde_json::from_str(&json).expect("failed to deserialize offering"); - - assert_eq!(offering, parsed_offering) - } -} diff --git a/crates/protocol/src/test_data.rs b/crates/protocol/src/test_data.rs deleted file mode 100644 index 324aa225..00000000 --- a/crates/protocol/src/test_data.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::messages::close::{Close, CloseData}; -use crate::messages::quote::{ - PaymentInstruction, PaymentInstructions, Quote, QuoteData, QuoteDetails, -}; -use crate::messages::Message; -use crate::resources::offering::{ - CreateOptions, Offering, OfferingData, PayinDetails, PayoutDetails, -}; -use crate::resources::Resource; -use chrono::Utc; -use credentials::pex::v2::{Constraints, Field, InputDescriptor, PresentationDefinition}; -use serde_json::{json, Value as JsonValue}; -use type_safe_id::{DynamicType, TypeSafeId}; - -#[cfg(test)] -pub struct TestData; - -#[cfg(test)] -impl TestData { - pub fn get_offering(from: String) -> Resource { - Offering::create(CreateOptions { - from, - data: OfferingData { - description: "my fake offering".to_string(), - payout_units_per_payin_unit: "2".to_string(), - payin: PayinDetails { - currency_code: "USD".to_string(), - ..Default::default() - }, - payout: PayoutDetails { - currency_code: "BTC".to_string(), - ..Default::default() - }, - required_claims: TestData::get_presentation_definition(), - }, - ..Default::default() - }) - .expect("failed to create offering") - } - - pub fn get_close(from: String, exchange_id: TypeSafeId) -> Message { - Close::create( - from, - "did:example:to_1234".to_string(), - exchange_id, - Some("I don't want to do business with you anymore".to_string()), - ) - .expect("failed to create Close") - } - - pub fn get_quote( - from: String, - to: String, - exchange_id: TypeSafeId, - ) -> Message { - Quote::create( - from, - to, - exchange_id, - QuoteData { - expires_at: Utc::now(), - payin: QuoteDetails { - currency_code: "USD".to_string(), - amount_subunits: "100".to_string(), - fee_subunits: Some("10".to_string()), - }, - payout: QuoteDetails { - currency_code: "BTC".to_string(), - amount_subunits: "2500".to_string(), - fee_subunits: None, - }, - payment_instructions: Some(PaymentInstructions { - payin: Some(PaymentInstruction { - link: Some("example.com/payin".to_string()), - instruction: Some("Hand me the cash".to_string()), - }), - payout: Some(PaymentInstruction { - link: None, - instruction: Some("BOLT 12".to_string()), - }), - }), - }, - ) - .expect("failed to create Quote") - } - - fn get_presentation_definition() -> PresentationDefinition { - PresentationDefinition { - id: "test-pd-id".to_string(), - name: Some("simple PD".to_string()), - purpose: Some("pd for testing".to_string()), - input_descriptors: vec![TestData::get_input_descriptor()], - ..Default::default() - } - } - - fn get_input_descriptor() -> InputDescriptor { - InputDescriptor { - id: "whatever".to_string(), - purpose: Some("id for testing".to_string()), - constraints: Constraints { - fields: Some(vec![Field { - path: vec!["$.credentialSubject.btcAddress".to_string()], - ..Default::default() - }]), - ..Default::default() - }, - ..Default::default() - } - } - - pub fn required_payment_details_schema() -> JsonValue { - json! { - r#" - { - "${'$'}schema": "http://json-schema.org/draft-07/schema", - "additionalProperties": false, - "type": "object", - "properties": { - "phoneNumber": { - "minLength": 12, - "pattern": "^+2547[0-9]{8}${'$'}", - "description": "Mobile Money account number of the Recipient", - "type": "string", - "title": "Phone Number", - "maxLength": 12 - }, - "accountHolderName": { - "pattern": "^[A-Za-zs'-]+${'$'}", - "description": "Name of the account holder as it appears on the Mobile Money account", - "type": "string", - "title": "Account Holder Name", - "maxLength": 32 - } - }, - "required": [ - "accountNumber", - "accountHolderName" - ] - } - "# - } - } -} diff --git a/crates/tbdex/src/lib.rs b/crates/tbdex/src/lib.rs index c194bfcc..69dad965 100644 --- a/crates/tbdex/src/lib.rs +++ b/crates/tbdex/src/lib.rs @@ -2,4 +2,4 @@ pub mod http_client; pub mod messages; pub mod resources; -mod signer; \ No newline at end of file +mod signer; diff --git a/crates/tbdex/src/messages/rfq.rs b/crates/tbdex/src/messages/rfq.rs index cd618e02..0c4930d1 100644 --- a/crates/tbdex/src/messages/rfq.rs +++ b/crates/tbdex/src/messages/rfq.rs @@ -229,7 +229,8 @@ mod tests { }, "1.0".to_string(), None, - ).unwrap(); + ) + .unwrap(); rfq.sign(bearer_did).unwrap(); diff --git a/tbdex-rs.code-workspace b/tbdex-rs.code-workspace deleted file mode 100644 index 66e7fcb2..00000000 --- a/tbdex-rs.code-workspace +++ /dev/null @@ -1,27 +0,0 @@ -{ - "folders": [ - { - "name": "root", - "path": "." - }, - { - "path": "crates/protocol" - } - ], - "settings": { - "files.exclude": { - "**/.git": true, - "**/.svn": true, - "**/.hg": true, - "**/CVS": true, - "**/.DS_Store": true, - "**/Thumbs.db": true, - "examples/**/_ftl": true, - "**/node_modules": true, - "**/go.work": true, - "**/go.work.sum": true, - ".hermit": true, - "**/*.zip": true, - } - } -}