use algonaut_client::{kmd::v1::Client, token::ApiToken, Headers};
use algonaut_core::{Address, MultisigSignature, ToMsgPack};
use algonaut_crypto::{Ed25519PublicKey, MasterDerivationKey};
use algonaut_model::kmd::v1::{
CreateWalletResponse, DeleteKeyResponse, DeleteMultisigResponse, ExportKeyResponse,
ExportMasterDerivationKeyResponse, ExportMultisigResponse, GenerateKeyResponse,
GetWalletInfoResponse, ImportKeyResponse, ImportMultisigResponse, InitWalletHandleResponse,
ListKeysResponse, ListMultisigResponse, ListWalletsResponse, ReleaseWalletHandleResponse,
RenameWalletResponse, RenewWalletHandleResponse, SignMultisigTransactionResponse,
SignTransactionResponse, VersionsResponse,
};
use algonaut_transaction::Transaction;
use crate::error::ServiceError;
#[derive(Debug)]
pub struct Kmd {
pub(crate) client: Client,
}
impl Kmd {
pub fn new(url: &str, token: &str) -> Result<Kmd, ServiceError> {
Self::with_headers(
url,
vec![("X-KMD-API-Token", &ApiToken::parse(token)?.to_string())],
)
}
pub fn with_headers(url: &str, headers: Headers) -> Result<Kmd, ServiceError> {
Ok(Kmd {
client: Client::new(url, headers)?,
})
}
pub async fn versions(&self) -> Result<VersionsResponse, ServiceError> {
Ok(self.client.versions().await?)
}
pub async fn list_wallets(&self) -> Result<ListWalletsResponse, ServiceError> {
Ok(self.client.list_wallets().await?)
}
pub async fn create_wallet(
&self,
wallet_name: &str,
wallet_password: &str,
wallet_driver_name: &str,
master_derivation_key: MasterDerivationKey,
) -> Result<CreateWalletResponse, ServiceError> {
Ok(self
.client
.create_wallet(
wallet_name,
wallet_password,
wallet_driver_name,
master_derivation_key,
)
.await?)
}
pub async fn init_wallet_handle(
&self,
wallet_id: &str,
wallet_password: &str,
) -> Result<InitWalletHandleResponse, ServiceError> {
Ok(self
.client
.init_wallet_handle(wallet_id, wallet_password)
.await?)
}
pub async fn release_wallet_handle(
&self,
wallet_handle: &str,
) -> Result<ReleaseWalletHandleResponse, ServiceError> {
Ok(self.client.release_wallet_handle(wallet_handle).await?)
}
pub async fn renew_wallet_handle(
&self,
wallet_handle: &str,
) -> Result<RenewWalletHandleResponse, ServiceError> {
Ok(self.client.renew_wallet_handle(wallet_handle).await?)
}
pub async fn rename_wallet(
&self,
wallet_id: &str,
wallet_password: &str,
new_name: &str,
) -> Result<RenameWalletResponse, ServiceError> {
Ok(self
.client
.rename_wallet(wallet_id, wallet_password, new_name)
.await?)
}
pub async fn get_wallet_info(
&self,
wallet_handle: &str,
) -> Result<GetWalletInfoResponse, ServiceError> {
Ok(self.client.get_wallet_info(wallet_handle).await?)
}
pub async fn export_master_derivation_key(
&self,
wallet_handle: &str,
wallet_password: &str,
) -> Result<ExportMasterDerivationKeyResponse, ServiceError> {
Ok(self
.client
.export_master_derivation_key(wallet_handle, wallet_password)
.await?)
}
pub async fn import_key(
&self,
wallet_handle: &str,
private_key: [u8; 32],
) -> Result<ImportKeyResponse, ServiceError> {
Ok(self.client.import_key(wallet_handle, private_key).await?)
}
pub async fn export_key(
&self,
wallet_handle: &str,
wallet_password: &str,
address: &Address,
) -> Result<ExportKeyResponse, ServiceError> {
Ok(self
.client
.export_key(wallet_handle, wallet_password, address)
.await?)
}
pub async fn generate_key(
&self,
wallet_handle: &str,
) -> Result<GenerateKeyResponse, ServiceError> {
Ok(self.client.generate_key(wallet_handle).await?)
}
pub async fn delete_key(
&self,
wallet_handle: &str,
wallet_password: &str,
address: &str,
) -> Result<DeleteKeyResponse, ServiceError> {
Ok(self
.client
.delete_key(wallet_handle, wallet_password, address)
.await?)
}
pub async fn list_keys(&self, wallet_handle: &str) -> Result<ListKeysResponse, ServiceError> {
Ok(self.client.list_keys(wallet_handle).await?)
}
pub async fn sign_transaction(
&self,
wallet_handle: &str,
wallet_password: &str,
transaction: &Transaction,
) -> Result<SignTransactionResponse, ServiceError> {
Ok(self
.client
.sign_transaction(wallet_handle, wallet_password, transaction.to_msg_pack()?)
.await?)
}
pub async fn list_multisig(
&self,
wallet_handle: &str,
) -> Result<ListMultisigResponse, ServiceError> {
Ok(self.client.list_multisig(wallet_handle).await?)
}
pub async fn import_multisig(
&self,
wallet_handle: &str,
version: u8,
threshold: u8,
pks: &[Ed25519PublicKey],
) -> Result<ImportMultisigResponse, ServiceError> {
Ok(self
.client
.import_multisig(wallet_handle, version, threshold, pks)
.await?)
}
pub async fn export_multisig(
&self,
wallet_handle: &str,
address: &str,
) -> Result<ExportMultisigResponse, ServiceError> {
Ok(self.client.export_multisig(wallet_handle, address).await?)
}
pub async fn delete_multisig(
&self,
wallet_handle: &str,
wallet_password: &str,
address: &str,
) -> Result<DeleteMultisigResponse, ServiceError> {
Ok(self
.client
.delete_multisig(wallet_handle, wallet_password, address)
.await?)
}
pub async fn sign_multisig_transaction(
&self,
wallet_handle: &str,
wallet_password: &str,
transaction: &Transaction,
public_key: Ed25519PublicKey,
partial_multisig: Option<MultisigSignature>,
) -> Result<SignMultisigTransactionResponse, ServiceError> {
Ok(self
.client
.sign_multisig_transaction(
wallet_handle,
wallet_password,
transaction.to_msg_pack()?,
public_key,
partial_multisig,
)
.await?)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_client_creation() {
let kmd = Kmd::new(
"http://example.com",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
);
assert!(kmd.ok().is_some());
}
#[test]
#[should_panic(expected = "")]
fn test_client_creation_with_empty_token() {
Kmd::new("http://example.com", "").unwrap();
}
#[test]
#[should_panic(expected = "")]
fn test_client_builder_with_empty_url() {
Kmd::new(
"",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
)
.unwrap();
}
}