use anyhow::Result;
use common::get_test_client;
use p256::elliptic_curve::SecretKey;
use privy_rs::{AuthorizationContext, PrivateKey, generated::types::*};
use tracing_test::traced_test;
use uuid::Uuid;
mod common;
#[tokio::test]
#[traced_test]
async fn test_wallets_e2e_quorum_workflow() -> Result<()> {
let client = get_test_client()?;
let wallet_idempotency_key = format!("wallet-{}", Uuid::new_v4());
tracing::info!("Starting comprehensive e2e quorum workflow test");
tracing::info!("Generating three P-256 private keys for 2-of-3 quorum");
let mut rng = rand::thread_rng();
let key1 = SecretKey::<p256::NistP256>::random(&mut rng);
let key2 = SecretKey::<p256::NistP256>::random(&mut rng);
let key3 = SecretKey::<p256::NistP256>::random(&mut rng);
let pubkey1 = key1.public_key().to_string();
let pubkey2 = key2.public_key().to_string();
let pubkey3 = key3.public_key().to_string();
tracing::info!("Generated public keys:");
tracing::info!("Key 1: {}", pubkey1);
tracing::info!("Key 2: {}", pubkey2);
tracing::info!("Key 3: {}", pubkey3);
tracing::info!("Creating 2-of-3 key quorum");
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)?
.as_secs();
let quorum_display_name =
KeyQuorumCreateRequestBodyDisplayName::try_from(format!("E2E Test Quorum {timestamp}").as_str())?;
let quorum_body = KeyQuorumCreateRequestBody {
authorization_threshold: Some(2.0), display_name: Some(quorum_display_name),
key_quorum_ids: vec![],
public_keys: vec![pubkey1, pubkey2, pubkey3],
user_ids: vec![],
};
let key_quorum = client.key_quorums().create(&quorum_body).await?;
tracing::info!("Created key quorum: {:?}", key_quorum);
tracing::info!(
"Creating new ethereum wallet with idempotency key: {}",
wallet_idempotency_key
);
let create_body = CreateWalletBody {
chain_type: WalletChainType::Ethereum,
additional_signers: None,
display_name: None,
external_id: None,
owner: None,
owner_id: Some(key_quorum.id.parse().unwrap()),
policy_ids: None,
};
let wallet = client
.wallets()
.create(Some(&wallet_idempotency_key), &create_body)
.await?;
let single_key_ctx = AuthorizationContext::new().push(PrivateKey::new(
key1.to_sec1_pem(der::pem::LineEnding::LF)
.unwrap()
.as_str()
.to_owned(),
));
tracing::info!("Testing transaction signing with only one key (should fail)");
let single_key_result = client.wallets().export(&wallet.id, &single_key_ctx).await;
match single_key_result {
Err(err) => {
tracing::info!("Single key signing correctly failed as expected: {:?}", err);
}
Ok(e) => {
tracing::error!("{:?}", e);
panic!("Single key signing should have failed but succeeded!");
}
}
tracing::info!("Testing transaction signing with three keys (should succeed)");
let three_key_ctx = {
single_key_ctx
.push(PrivateKey::new(
key2.to_sec1_pem(der::pem::LineEnding::LF)
.unwrap()
.as_str()
.to_owned(),
))
.push(PrivateKey::new(
key3.to_sec1_pem(der::pem::LineEnding::LF)
.unwrap()
.as_str()
.to_owned(),
))
};
let three_key_result =
debug_response!(client.wallets().export(&wallet.id, &three_key_ctx)).await;
tracing::info!("Three key signing successful: {:?}", three_key_result);
tracing::info!("E2E quorum workflow test completed successfully!");
tracing::info!("Wallet ID: {}", wallet.id);
tracing::info!("Used idempotency keys:");
tracing::info!(" Wallet: {}", wallet_idempotency_key);
Ok(())
}
#[tokio::test]
#[traced_test]
async fn test_rpc_e2e_quorum_workflow() -> Result<()> {
let client = common::get_test_client()?;
let wallet_idempotency_key = format!("wallet-{}", Uuid::new_v4());
let sign1_idempotency_key = format!("sign1-{}", Uuid::new_v4());
let sign2_idempotency_key = format!("sign2-{}", Uuid::new_v4());
tracing::info!("Starting comprehensive e2e quorum workflow test");
tracing::info!("Generating three P-256 private keys for 2-of-3 quorum");
let mut rng = rand::thread_rng();
let key1 = SecretKey::<p256::NistP256>::random(&mut rng);
let key2 = SecretKey::<p256::NistP256>::random(&mut rng);
let key3 = SecretKey::<p256::NistP256>::random(&mut rng);
let pubkey1 = key1.public_key().to_string();
let pubkey2 = key2.public_key().to_string();
let pubkey3 = key3.public_key().to_string();
tracing::info!("Generated public keys:");
tracing::info!("Key 1: {}", pubkey1);
tracing::info!("Key 2: {}", pubkey2);
tracing::info!("Key 3: {}", pubkey3);
tracing::info!("Creating 2-of-3 key quorum");
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)?
.as_secs();
let quorum_display_name =
KeyQuorumCreateRequestBodyDisplayName::try_from(format!("E2E Test Quorum {timestamp}").as_str())?;
let quorum_body = KeyQuorumCreateRequestBody {
authorization_threshold: Some(2.0), display_name: Some(quorum_display_name),
key_quorum_ids: vec![],
public_keys: vec![pubkey1, pubkey2, pubkey3],
user_ids: vec![],
};
let key_quorum = client.key_quorums().create(&quorum_body).await?;
tracing::info!("Created key quorum: {:?}", key_quorum);
tracing::info!(
"Creating new ethereum wallet with idempotency key: {}",
wallet_idempotency_key
);
let create_body = CreateWalletBody {
chain_type: WalletChainType::Ethereum,
additional_signers: None,
display_name: None,
external_id: None,
owner: None,
owner_id: Some(key_quorum.id.parse().unwrap()),
policy_ids: None,
};
let wallet = client
.wallets()
.create(Some(&wallet_idempotency_key), &create_body)
.await?;
let single_key_ctx = AuthorizationContext::new().push(PrivateKey::new(
key1.to_sec1_pem(der::pem::LineEnding::LF)
.unwrap()
.as_str()
.to_owned(),
));
tracing::info!("Testing transaction signing with only one key (should fail)");
let single_key_result = client
.wallets()
.ethereum()
.sign_message(
&wallet.id,
"hello world",
&single_key_ctx,
Some(&sign1_idempotency_key),
)
.await;
match single_key_result {
Err(err) => {
tracing::info!("Single key signing correctly failed as expected: {:?}", err);
}
Ok(e) => {
tracing::error!("{:?}", e);
panic!("Single key signing should have failed but succeeded!");
}
}
tracing::info!("Testing transaction signing with three keys (should succeed)");
let three_key_ctx = {
single_key_ctx
.push(PrivateKey::new(
key2.to_sec1_pem(der::pem::LineEnding::LF)
.unwrap()
.as_str()
.to_owned(),
))
.push(PrivateKey::new(
key3.to_sec1_pem(der::pem::LineEnding::LF)
.unwrap()
.as_str()
.to_owned(),
))
};
let three_key_result = debug_response!(client.wallets().ethereum().sign_message(
&wallet.id,
"hello world",
&three_key_ctx,
Some(&sign2_idempotency_key)
))
.await;
tracing::info!("Three key signing successful: {:?}", three_key_result);
tracing::info!("E2E quorum workflow test completed successfully!");
tracing::info!("Wallet ID: {}", wallet.id);
tracing::info!("Used idempotency keys:");
tracing::info!(" Wallet: {}", wallet_idempotency_key);
tracing::info!(" Sign 1: {}", sign1_idempotency_key);
tracing::info!(" Sign 2: {}", sign2_idempotency_key);
Ok(())
}