secret.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. //! Secret types for NUT-18: Payment Requests
  2. use serde::{Deserialize, Serialize};
  3. use crate::nuts::nut10::Kind;
  4. use crate::nuts::{Nut10Secret, SpendingConditions};
  5. /// Nut10Secret without nonce for payment requests
  6. #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
  7. pub struct Nut10SecretRequest {
  8. /// Kind of the spending condition
  9. #[serde(rename = "k")]
  10. pub kind: Kind,
  11. /// Secret data
  12. #[serde(rename = "d")]
  13. pub data: String,
  14. /// Additional data committed to and can be used for feature extensions
  15. #[serde(rename = "t", skip_serializing_if = "Option::is_none")]
  16. pub tags: Option<Vec<Vec<String>>>,
  17. }
  18. impl Nut10SecretRequest {
  19. /// Create a new Nut10SecretRequest
  20. pub fn new<S, V>(kind: Kind, data: S, tags: Option<V>) -> Self
  21. where
  22. S: Into<String>,
  23. V: Into<Vec<Vec<String>>>,
  24. {
  25. Self {
  26. kind,
  27. data: data.into(),
  28. tags: tags.map(Into::into),
  29. }
  30. }
  31. }
  32. impl From<Nut10Secret> for Nut10SecretRequest {
  33. fn from(secret: Nut10Secret) -> Self {
  34. Self {
  35. kind: secret.kind(),
  36. data: secret.secret_data().data().to_string(),
  37. tags: secret.secret_data().tags().cloned(),
  38. }
  39. }
  40. }
  41. impl From<Nut10SecretRequest> for Nut10Secret {
  42. fn from(value: Nut10SecretRequest) -> Self {
  43. Self::new(value.kind, value.data, value.tags)
  44. }
  45. }
  46. impl From<SpendingConditions> for Nut10SecretRequest {
  47. fn from(conditions: SpendingConditions) -> Self {
  48. match conditions {
  49. SpendingConditions::P2PKConditions { data, conditions } => {
  50. Self::new(Kind::P2PK, data.to_hex(), conditions)
  51. }
  52. SpendingConditions::HTLCConditions { data, conditions } => {
  53. Self::new(Kind::HTLC, data.to_string(), conditions)
  54. }
  55. }
  56. }
  57. }
  58. #[cfg(test)]
  59. mod tests {
  60. use super::*;
  61. #[test]
  62. fn test_nut10_secret_request_serialization() {
  63. let request = Nut10SecretRequest::new(
  64. Kind::P2PK,
  65. "026562efcfadc8e86d44da6a8adf80633d974302e62c850774db1fb36ff4cc7198",
  66. Some(vec![vec!["key".to_string(), "value".to_string()]]),
  67. );
  68. let json = serde_json::to_string(&request).unwrap();
  69. // Verify json has abbreviated field names
  70. assert!(json.contains(r#""k":"P2PK""#));
  71. assert!(json.contains(r#""d":"026562"#));
  72. assert!(json.contains(r#""t":[["key","#));
  73. }
  74. #[test]
  75. fn test_roundtrip_serialization() {
  76. let original = Nut10SecretRequest {
  77. kind: Kind::P2PK,
  78. data: "test_data".into(),
  79. tags: Some(vec![vec!["key".to_string(), "value".to_string()]]),
  80. };
  81. let json = serde_json::to_string(&original).unwrap();
  82. let decoded: Nut10SecretRequest = serde_json::from_str(&json).unwrap();
  83. assert_eq!(original, decoded);
  84. }
  85. #[test]
  86. fn test_from_nut10_secret() {
  87. let secret = Nut10Secret::new(
  88. Kind::P2PK,
  89. "test_data",
  90. Some(vec![vec!["key".to_string(), "value".to_string()]]),
  91. );
  92. let request: Nut10SecretRequest = secret.clone().into();
  93. assert_eq!(request.kind, secret.kind());
  94. assert_eq!(request.data, secret.secret_data().data());
  95. assert_eq!(request.tags, secret.secret_data().tags().cloned());
  96. }
  97. #[test]
  98. fn test_into_nut10_secret() {
  99. let request = Nut10SecretRequest {
  100. kind: Kind::HTLC,
  101. data: "test_hash".into(),
  102. tags: None,
  103. };
  104. let secret: Nut10Secret = request.clone().into();
  105. assert_eq!(secret.kind(), request.kind);
  106. assert_eq!(secret.secret_data().data(), request.data);
  107. assert_eq!(secret.secret_data().tags(), request.tags.as_ref());
  108. }
  109. }