use dynamic_waas_sdk_core::{
api::{KeygenCompleteEvent, SignMessageReq},
sse::{stream_sse_with_callback, SseEventData},
Error, Result, ServerKeyShare,
};
use dynamic_waas_sdk_mpc::{Ed25519Signer, RoomUuid, SecretShare};
use tracing::{debug, instrument};
use crate::client::DynamicWalletClient;
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct SignOptsEd25519 {
pub wallet_id: String,
pub message: Vec<u8>,
pub secret_share: ServerKeyShare,
}
impl SignOptsEd25519 {
pub fn new(
wallet_id: impl Into<String>,
message: Vec<u8>,
secret_share: ServerKeyShare,
) -> Self {
Self {
wallet_id: wallet_id.into(),
message,
secret_share,
}
}
}
#[instrument(skip(client, opts), fields(wallet_id = %opts.wallet_id))]
pub async fn run_sign_ed25519(
client: &DynamicWalletClient,
opts: SignOptsEd25519,
) -> Result<[u8; 64]> {
if !client.is_authenticated() {
return Err(Error::Authentication(crate::AUTH_REQUIRED_MSG.into()));
}
let msg_hex = hex::encode(&opts.message);
let body = SignMessageReq {
message: msg_hex,
is_formatted: false,
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 secret_share = SecretShare::from_string(opts.secret_share.secret_share);
let message = opts.message.clone();
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 ed25519 sign");
let signer = Ed25519Signer::new(host_url);
let room = RoomUuid::new(event.room_id);
let sig = signer.sign(&room, &secret_share, &message).await?;
Ok::<_, Error>(sig)
})
.await?;
Ok(signature)
}