nut15.rs 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. //! NUT-15: Multipart payments
  2. //!
  3. //! <https://github.com/cashubtc/nuts/blob/main/15.md>
  4. use serde::{Deserialize, Deserializer, Serialize};
  5. use super::{CurrencyUnit, PaymentMethod};
  6. use crate::Amount;
  7. /// Multi-part payment
  8. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
  9. #[serde(rename = "lowercase")]
  10. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  11. pub struct Mpp {
  12. /// Amount
  13. pub amount: Amount,
  14. }
  15. /// Mpp Method Settings
  16. #[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
  17. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  18. pub struct MppMethodSettings {
  19. /// Payment Method e.g. bolt11
  20. pub method: PaymentMethod,
  21. /// Currency Unit e.g. sat
  22. pub unit: CurrencyUnit,
  23. }
  24. /// Mpp Settings
  25. #[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize)]
  26. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema), schema(as = nut15::Settings))]
  27. pub struct Settings {
  28. /// Method settings
  29. pub methods: Vec<MppMethodSettings>,
  30. }
  31. // Custom deserialization to handle both array and object formats
  32. impl<'de> Deserialize<'de> for Settings {
  33. fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  34. where
  35. D: Deserializer<'de>,
  36. {
  37. #[derive(Deserialize)]
  38. #[serde(untagged)]
  39. enum SettingsFormat {
  40. Array(Vec<MppMethodSettings>),
  41. Object { methods: Vec<MppMethodSettings> },
  42. }
  43. let format = SettingsFormat::deserialize(deserializer)?;
  44. match format {
  45. SettingsFormat::Array(methods) => Ok(Settings { methods }),
  46. SettingsFormat::Object { methods } => Ok(Settings { methods }),
  47. }
  48. }
  49. }
  50. #[cfg(test)]
  51. mod tests {
  52. use super::*;
  53. use crate::PaymentMethod;
  54. #[test]
  55. fn test_nut15_settings_deserialization() {
  56. // Test array format
  57. let array_json = r#"[{"method":"bolt11","unit":"sat"}]"#;
  58. let settings: Settings = serde_json::from_str(array_json).unwrap();
  59. assert_eq!(settings.methods.len(), 1);
  60. assert_eq!(settings.methods[0].method, PaymentMethod::Bolt11);
  61. assert_eq!(settings.methods[0].unit, CurrencyUnit::Sat);
  62. // Test object format
  63. let object_json = r#"{"methods":[{"method":"bolt11","unit":"sat"}]}"#;
  64. let settings: Settings = serde_json::from_str(object_json).unwrap();
  65. assert_eq!(settings.methods.len(), 1);
  66. assert_eq!(settings.methods[0].method, PaymentMethod::Bolt11);
  67. assert_eq!(settings.methods[0].unit, CurrencyUnit::Sat);
  68. }
  69. #[test]
  70. fn test_nut15_settings_serialization() {
  71. let settings = Settings {
  72. methods: vec![MppMethodSettings {
  73. method: PaymentMethod::Bolt11,
  74. unit: CurrencyUnit::Sat,
  75. }],
  76. };
  77. let json = serde_json::to_string(&settings).unwrap();
  78. assert_eq!(json, r#"{"methods":[{"method":"bolt11","unit":"sat"}]}"#);
  79. }
  80. }