use dynamic_waas_sdk_core::{
api::{KeygenCompleteEvent, SignMessageReq},
sse::{stream_sse_with_callback, SseEventData},
Error, Result, ServerKeyShare,
};
use dynamic_waas_sdk_mpc::{EcdsaSignature, EcdsaSigner, MessageHash, RoomUuid, SecretShare};
use tracing::{debug, instrument};
use crate::client::DynamicWalletClient;
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct SignOpts {
pub wallet_id: String,
pub msg_hash: [u8; 32],
pub server_message: String,
pub server_is_formatted: bool,
pub secret_share: ServerKeyShare,
pub derivation_path: Vec<u32>,
}
impl SignOpts {
pub fn new(
wallet_id: impl Into<String>,
msg_hash: [u8; 32],
server_message: impl Into<String>,
server_is_formatted: bool,
secret_share: ServerKeyShare,
derivation_path: Vec<u32>,
) -> Self {
Self {
wallet_id: wallet_id.into(),
msg_hash,
server_message: server_message.into(),
server_is_formatted,
secret_share,
derivation_path,
}
}
}
#[instrument(skip(client, opts), fields(wallet_id = %opts.wallet_id))]
pub async fn run_sign_ecdsa(
client: &DynamicWalletClient,
opts: SignOpts,
) -> Result<EcdsaSignature> {
if !client.is_authenticated() {
return Err(Error::Authentication(crate::AUTH_REQUIRED_MSG.into()));
}
let body = SignMessageReq {
message: opts.server_message,
is_formatted: opts.server_is_formatted,
server_is_formatted: None,
context: None,
};
let response = client
.api()
.sign_message_with_callback(&opts.wallet_id, &body)
.await?;
let host_url = client.base_mpc_relay_url().to_string();
let msg_hash = opts.msg_hash;
let derivation_path = opts.derivation_path.clone();
let secret_share = SecretShare::from_string(opts.secret_share.secret_share);
let (signature, _ceremony_data) =
stream_sse_with_callback(response, "room_created", move |trigger| async move {
let event: KeygenCompleteEvent = match trigger {
SseEventData::Json(v) => serde_json::from_value(v).map_err(Error::from)?,
SseEventData::Raw(s) => {
return Err(Error::Sse(format!(
"room_created payload was not JSON: {s}"
)))
}
};
debug!(room_id = %event.room_id, "running MPC sign");
let signer = EcdsaSigner::new(host_url);
let room = RoomUuid::new(event.room_id);
let hash = MessageHash(msg_hash);
let sig = signer
.sign(&room, &secret_share, &hash, &derivation_path)
.await?;
Ok::<_, Error>(sig)
})
.await?;
Ok(signature)
}