use alloy::primitives::hex::encode_prefixed;
use alloy::signers::local::PrivateKeySigner;
use alloy_sol_types::{eip712_domain, Eip712Domain};
use alloy::signers::Signer as AlloySigner;
use crate::clob::{ClobError, Result};
use super::model::{CLOB_DOMAIN_NAME, CLOB_VERSION, MSG_TO_SIGN};
alloy::sol! {
#[derive(Debug)]
struct ClobAuth {
address address;
string timestamp;
uint256 nonce;
string message;
}
}
pub fn get_clob_auth_domain(chain_id: u64) -> Eip712Domain {
eip712_domain! {
name: CLOB_DOMAIN_NAME,
version: CLOB_VERSION,
chain_id: chain_id,
}
}
pub async fn sign_clob_auth_message(
signer: &PrivateKeySigner,
chain_id: u64,
timestamp: u64,
nonce: u64,
) -> Result<String> {
let message = ClobAuth {
address: signer.address(),
timestamp: timestamp.to_string(),
nonce: alloy::primitives::U256::from(nonce),
message: MSG_TO_SIGN.to_string(),
};
let domain = get_clob_auth_domain(chain_id);
let signature = signer
.sign_typed_data(&message, &domain)
.await
.map_err(|e| ClobError::SigningError(e.to_string()))?;
Ok(encode_prefixed(signature.as_bytes()))
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[tokio::test]
async fn test_clob_auth_signing() {
let private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
let signer = PrivateKeySigner::from_str(private_key).unwrap();
let timestamp = 1234567890u64;
let nonce = 1u64;
let chain_id = 137u64;
let signature = sign_clob_auth_message(&signer, chain_id, timestamp, nonce).await;
assert!(signature.is_ok());
let sig = signature.unwrap();
assert!(sig.starts_with("0x"));
assert_eq!(sig.len(), 132); }
#[tokio::test]
async fn test_clob_auth_signature_matches_python() {
let private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
let signer = PrivateKeySigner::from_str(private_key).unwrap();
let chain_id = 80002u64;
let timestamp = 10000000u64;
let nonce = 23u64;
let signature = sign_clob_auth_message(&signer, chain_id, timestamp, nonce)
.await
.unwrap();
let expected_sig = "0xf62319a987514da40e57e2f4d7529f7bac38f0355bd88bb5adbb3768d80de6c1682518e0af677d5260366425f4361e7b70c25ae232aff0ab2331e2b164a1aedc1b";
println!("Rust signature: {}", signature);
println!("Python signature: {}", expected_sig);
assert_eq!(
signature.to_lowercase(),
expected_sig.to_lowercase(),
"Rust signature should match Python signature exactly"
);
}
}