1use crate::SeismicTransactionSigned;
4use alloy_consensus::SignableTransaction;
5use alloy_dyn_abi::TypedData;
6use alloy_eips::eip2718::Encodable2718;
7use alloy_network::{EthereumWallet, TransactionBuilder};
8use alloy_primitives::{aliases::U96, hex_literal, Address, Bytes, Signature, TxKind, U256};
9use alloy_rpc_types::{TransactionInput, TransactionRequest};
10use alloy_signer_local::PrivateKeySigner;
11use core::str::FromStr;
12use enr::EnrKey;
13use k256::ecdsa::SigningKey;
14use reth_enclave::MockEnclaveServer;
15use secp256k1::{PublicKey, SecretKey};
16use seismic_alloy_consensus::{
17 SeismicTxEnvelope, SeismicTypedTransaction, TxSeismic, TxSeismicElements, TypedDataRequest,
18};
19use seismic_alloy_rpc_types::SeismicTransactionRequest;
20use seismic_enclave::keys::GetPurposeKeysRequest;
21
22pub fn get_network_public_key() -> PublicKey {
24 let purpose_keys = MockEnclaveServer::get_purpose_keys(GetPurposeKeysRequest { epoch: 0 });
25 purpose_keys.tx_io_pk
26}
27
28pub fn get_client_io_sk() -> SecretKey {
30 let private_key_bytes =
31 hex_literal::hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
32 SecretKey::from_slice(&private_key_bytes).expect("Invalid private key")
33}
34
35pub fn get_signing_private_key() -> SigningKey {
37 let private_key_bytes =
38 hex_literal::hex!("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80");
39 let signing_key =
40 SigningKey::from_bytes(&private_key_bytes.into()).expect("Invalid private key");
41 signing_key
42}
43
44pub fn get_wrong_private_key() -> SecretKey {
46 let private_key_bytes =
47 hex_literal::hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1e");
48 SecretKey::from_slice(&private_key_bytes).expect("Invalid private key")
49}
50
51pub fn get_encryption_nonce() -> U96 {
53 U96::MAX
54}
55
56pub fn get_seismic_elements() -> TxSeismicElements {
58 TxSeismicElements {
59 encryption_pubkey: get_client_io_sk().public(),
60 encryption_nonce: get_encryption_nonce(),
61 message_version: 0,
62 }
63}
64
65pub fn client_encrypt(plaintext: &Bytes) -> Result<Bytes, anyhow::Error> {
67 get_seismic_elements().client_encrypt(plaintext, &get_network_public_key(), &get_client_io_sk())
68}
69
70pub fn client_decrypt(ciphertext: &Bytes) -> Result<Bytes, anyhow::Error> {
72 get_seismic_elements().client_decrypt(
73 ciphertext,
74 &get_network_public_key(),
75 &get_client_io_sk(),
76 )
77}
78
79pub fn get_plaintext() -> Bytes {
81 Bytes::from_str("24a7f0b7000000000000000000000000000000000000000000000000000000000000000b")
82 .unwrap()
83}
84
85pub fn get_ciphertext() -> Bytes {
87 let encrypted_data = client_encrypt(&get_plaintext()).unwrap();
88 encrypted_data
89}
90
91pub fn get_seismic_tx() -> TxSeismic {
93 let ciphertext = get_ciphertext();
94 TxSeismic {
95 chain_id: 5123, nonce: 1,
97 gas_price: 20000000000,
98 gas_limit: 210000,
99 to: alloy_primitives::TxKind::Call(
100 Address::from_str("0x5fbdb2315678afecb367f032d93f642f64180aa3").unwrap(),
101 ),
102 value: U256::ZERO,
103 input: Bytes::copy_from_slice(&ciphertext),
104 seismic_elements: get_seismic_elements(),
105 }
106}
107
108pub fn sign_seismic_tx(tx: &TxSeismic, signing_sk: &SigningKey) -> Signature {
110 let _signature = signing_sk
111 .clone()
112 .sign_prehash_recoverable(tx.signature_hash().as_slice())
113 .expect("Failed to sign");
114
115 let recoverid = _signature.1;
116 let _signature = _signature.0;
117
118 let signature = Signature::new(
119 U256::from_be_slice(_signature.r().to_bytes().as_slice()),
120 U256::from_be_slice(_signature.s().to_bytes().as_slice()),
121 recoverid.is_y_odd(),
122 );
123
124 signature
125}
126
127pub fn sign_seismic_typed_tx(
129 typed_data: &SeismicTypedTransaction,
130 signing_sk: &SigningKey,
131) -> Signature {
132 let sig_hash = typed_data.signature_hash();
133 let sig = signing_sk.sign_prehash_recoverable(&sig_hash.as_slice()).unwrap();
134 let recoverid = sig.1;
135
136 let signature = Signature::new(
137 U256::from_be_slice(sig.0.r().to_bytes().as_slice()),
138 U256::from_be_slice(sig.0.s().to_bytes().as_slice()),
139 recoverid.is_y_odd(),
140 );
141 signature
142}
143
144pub fn get_signed_seismic_tx() -> SeismicTransactionSigned {
146 let signing_sk = get_signing_private_key();
147 let tx = get_seismic_tx();
148 let signature = sign_seismic_tx(&tx, &signing_sk);
149 SignableTransaction::into_signed(tx, signature).into()
150}
151
152pub fn get_signed_seismic_tx_encoding() -> Vec<u8> {
154 let signed_tx = get_signed_seismic_tx();
155 let mut encoding = Vec::new();
156
157 signed_tx.encode_2718(&mut encoding);
158 encoding
159}
160
161pub async fn get_unsigned_seismic_tx_request(
163 sk_wallet: &PrivateKeySigner,
164 nonce: u64,
165 to: TxKind,
166 chain_id: u64,
167 plaintext: Bytes,
168) -> SeismicTransactionRequest {
169 SeismicTransactionRequest {
170 inner: TransactionRequest {
171 from: Some(sk_wallet.address()),
172 nonce: Some(nonce),
173 value: Some(U256::from(0)),
174 to: Some(to),
175 gas: Some(6000000),
176 gas_price: Some(20e9 as u128),
177 chain_id: Some(chain_id),
178 input: TransactionInput {
179 input: Some(client_encrypt(&plaintext).unwrap()),
180 data: None,
181 },
182 transaction_type: Some(TxSeismic::TX_TYPE),
183 ..Default::default()
184 },
185 seismic_elements: Some(get_seismic_elements()),
186 }
187}
188
189pub async fn sign_tx(wallet: PrivateKeySigner, tx: SeismicTransactionRequest) -> SeismicTxEnvelope {
191 let signer = EthereumWallet::from(wallet);
192 <SeismicTransactionRequest as TransactionBuilder<seismic_alloy_network::Seismic>>::build(
193 tx, &signer,
194 )
195 .await
196 .unwrap()
197}
198
199pub async fn get_signed_seismic_tx_bytes(
201 sk_wallet: &PrivateKeySigner,
202 nonce: u64,
203 to: TxKind,
204 chain_id: u64,
205 plaintext: Bytes,
206) -> Bytes {
207 let tx = get_unsigned_seismic_tx_request(sk_wallet, nonce, to, chain_id, plaintext).await;
208 let signed_inner = sign_tx(sk_wallet.clone(), tx).await;
209 <SeismicTxEnvelope as Encodable2718>::encoded_2718(&signed_inner).into()
210}
211
212pub async fn get_unsigned_seismic_tx_typed_data(
214 sk_wallet: &PrivateKeySigner,
215 nonce: u64,
216 to: TxKind,
217 chain_id: u64,
218 decrypted_input: Bytes,
219) -> TypedData {
220 let tx_request =
221 get_unsigned_seismic_tx_request(sk_wallet, nonce, to, chain_id, decrypted_input).await;
222 let typed_tx = tx_request.build_typed_tx().unwrap();
223 match typed_tx {
224 SeismicTypedTransaction::Seismic(seismic) => seismic.eip712_to_type_data(),
225 _ => panic!("Typed transaction is not a seismic transaction"),
226 }
227}
228
229pub async fn get_signed_seismic_tx_typed_data(
231 sk_wallet: &PrivateKeySigner,
232 nonce: u64,
233 to: TxKind,
234 chain_id: u64,
235 plaintext: Bytes,
236) -> TypedDataRequest {
237 let tx = get_unsigned_seismic_tx_request(sk_wallet, nonce, to, chain_id, plaintext).await;
238 tx.seismic_elements.unwrap().message_version = 2;
239 let signed = sign_tx(sk_wallet.clone(), tx).await;
240
241 match signed {
242 SeismicTxEnvelope::Seismic(tx) => tx.into(),
243 _ => panic!("Signed transaction is not a seismic transaction"),
244 }
245}