Skip to main content

circle_user_controlled_wallets/models/
signing.rs

1//! Signing resource models for the Circle User-Controlled Wallets API.
2//!
3//! Contains request types for message and transaction signing endpoints.
4//! All signing responses return a `challengeId` — the actual signing is
5//! completed on the client side via the Circle Web3 Services mobile SDK.
6
7use serde::{Deserialize, Serialize};
8
9// ── Request bodies ────────────────────────────────────────────────────────────
10
11/// Request body for `signMessage`.
12#[derive(Debug, Clone, Deserialize, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub struct SignMessageRequest {
15    /// The message to sign (plain text or hex-encoded bytes).
16    pub message: String,
17    /// ID of the wallet that should sign.
18    pub wallet_id: String,
19    /// If `true`, `message` is interpreted as a hex-encoded byte string.
20    pub encoded_by_hex: Option<bool>,
21    /// Optional memo stored alongside the signing request.
22    pub memo: Option<String>,
23}
24
25/// Request body for `signTypedData`.
26#[derive(Debug, Clone, Deserialize, Serialize)]
27#[serde(rename_all = "camelCase")]
28pub struct SignTypedDataRequest {
29    /// EIP-712 typed data as a JSON string.
30    pub data: String,
31    /// ID of the wallet that should sign.
32    pub wallet_id: String,
33    /// Optional memo stored alongside the signing request.
34    pub memo: Option<String>,
35}
36
37/// Request body for `signTransaction`.
38#[derive(Debug, Clone, Deserialize, Serialize)]
39#[serde(rename_all = "camelCase")]
40pub struct SignTransactionRequest {
41    /// ID of the wallet that should sign.
42    pub wallet_id: String,
43    /// Raw unsigned transaction bytes (hex-encoded).
44    pub raw_transaction: Option<String>,
45    /// Transaction fields as a JSON string.
46    pub transaction: Option<String>,
47    /// Optional memo stored alongside the signing request.
48    pub memo: Option<String>,
49}
50
51// ── Tests ─────────────────────────────────────────────────────────────────────
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn sign_message_request_camel_case() -> Result<(), Box<dyn std::error::Error>> {
59        let req = SignMessageRequest {
60            message: "hello".to_string(),
61            wallet_id: "w1".to_string(),
62            encoded_by_hex: Some(false),
63            memo: Some("test".to_string()),
64        };
65        let s = serde_json::to_string(&req)?;
66        assert!(s.contains("walletId"), "{s}");
67        assert!(s.contains("encodedByHex"), "{s}");
68        Ok(())
69    }
70
71    #[test]
72    fn sign_typed_data_request_round_trip() -> Result<(), Box<dyn std::error::Error>> {
73        let req = SignTypedDataRequest {
74            data: r#"{"types":{}}"#.to_string(),
75            wallet_id: "w2".to_string(),
76            memo: None,
77        };
78        let json = serde_json::to_string(&req)?;
79        let decoded: SignTypedDataRequest = serde_json::from_str(&json)?;
80        assert_eq!(decoded.wallet_id, "w2");
81        Ok(())
82    }
83}