1use crate::error::AptosResult;
4use crate::transaction::authenticator::TransactionAuthenticator;
5use crate::transaction::payload::TransactionPayload;
6use crate::types::{AccountAddress, ChainId, HashValue};
7use serde::{Deserialize, Serialize};
8
9#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
15pub struct RawTransaction {
16 pub sender: AccountAddress,
18 pub sequence_number: u64,
20 pub payload: TransactionPayload,
22 pub max_gas_amount: u64,
24 pub gas_unit_price: u64,
26 pub expiration_timestamp_secs: u64,
28 pub chain_id: ChainId,
30}
31
32impl RawTransaction {
33 pub fn new(
35 sender: AccountAddress,
36 sequence_number: u64,
37 payload: TransactionPayload,
38 max_gas_amount: u64,
39 gas_unit_price: u64,
40 expiration_timestamp_secs: u64,
41 chain_id: ChainId,
42 ) -> Self {
43 Self {
44 sender,
45 sequence_number,
46 payload,
47 max_gas_amount,
48 gas_unit_price,
49 expiration_timestamp_secs,
50 chain_id,
51 }
52 }
53
54 pub fn signing_message(&self) -> AptosResult<Vec<u8>> {
63 let prefix = crate::crypto::sha3_256(b"APTOS::RawTransaction");
64 let bcs_bytes = aptos_bcs::to_bytes(self).map_err(crate::error::AptosError::bcs)?;
65
66 let mut message = Vec::with_capacity(prefix.len() + bcs_bytes.len());
67 message.extend_from_slice(&prefix);
68 message.extend_from_slice(&bcs_bytes);
69 Ok(message)
70 }
71
72 pub fn to_bcs(&self) -> AptosResult<Vec<u8>> {
78 aptos_bcs::to_bytes(self).map_err(crate::error::AptosError::bcs)
79 }
80}
81
82#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
94pub struct RawTransactionOrderless {
95 pub sender: AccountAddress,
97 pub nonce: Vec<u8>,
99 pub payload: TransactionPayload,
101 pub max_gas_amount: u64,
103 pub gas_unit_price: u64,
105 pub expiration_timestamp_secs: u64,
108 pub chain_id: ChainId,
110}
111
112impl RawTransactionOrderless {
113 pub fn new(
115 sender: AccountAddress,
116 payload: TransactionPayload,
117 max_gas_amount: u64,
118 gas_unit_price: u64,
119 expiration_timestamp_secs: u64,
120 chain_id: ChainId,
121 ) -> Self {
122 let mut nonce = vec![0u8; 32];
124 rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut nonce);
125 Self {
126 sender,
127 nonce,
128 payload,
129 max_gas_amount,
130 gas_unit_price,
131 expiration_timestamp_secs,
132 chain_id,
133 }
134 }
135
136 pub fn with_nonce(
138 sender: AccountAddress,
139 nonce: Vec<u8>,
140 payload: TransactionPayload,
141 max_gas_amount: u64,
142 gas_unit_price: u64,
143 expiration_timestamp_secs: u64,
144 chain_id: ChainId,
145 ) -> Self {
146 Self {
147 sender,
148 nonce,
149 payload,
150 max_gas_amount,
151 gas_unit_price,
152 expiration_timestamp_secs,
153 chain_id,
154 }
155 }
156
157 pub fn signing_message(&self) -> AptosResult<Vec<u8>> {
163 let prefix = crate::crypto::sha3_256(b"APTOS::RawTransactionOrderless");
164 let bcs_bytes = aptos_bcs::to_bytes(self).map_err(crate::error::AptosError::bcs)?;
165
166 let mut message = Vec::with_capacity(prefix.len() + bcs_bytes.len());
167 message.extend_from_slice(&prefix);
168 message.extend_from_slice(&bcs_bytes);
169 Ok(message)
170 }
171
172 pub fn to_bcs(&self) -> AptosResult<Vec<u8>> {
178 aptos_bcs::to_bytes(self).map_err(crate::error::AptosError::bcs)
179 }
180}
181
182#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
184pub struct SignedTransactionOrderless {
185 pub raw_txn: RawTransactionOrderless,
187 pub authenticator: TransactionAuthenticator,
189}
190
191impl SignedTransactionOrderless {
192 pub fn new(raw_txn: RawTransactionOrderless, authenticator: TransactionAuthenticator) -> Self {
194 Self {
195 raw_txn,
196 authenticator,
197 }
198 }
199
200 pub fn to_bcs(&self) -> AptosResult<Vec<u8>> {
206 aptos_bcs::to_bytes(self).map_err(crate::error::AptosError::bcs)
207 }
208
209 pub fn sender(&self) -> AccountAddress {
211 self.raw_txn.sender
212 }
213
214 pub fn nonce(&self) -> &[u8] {
216 &self.raw_txn.nonce
217 }
218
219 pub fn hash(&self) -> AptosResult<HashValue> {
225 let bcs_bytes = self.to_bcs()?;
226 let prefix = crate::crypto::sha3_256(b"APTOS::Transaction");
227
228 let mut data = Vec::with_capacity(prefix.len() + 1 + bcs_bytes.len());
229 data.extend_from_slice(&prefix);
230 data.push(2);
232 data.extend_from_slice(&bcs_bytes);
233
234 Ok(HashValue::new(crate::crypto::sha3_256(&data)))
235 }
236}
237
238#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
240pub struct SignedTransaction {
241 pub raw_txn: RawTransaction,
243 pub authenticator: TransactionAuthenticator,
245}
246
247impl SignedTransaction {
248 pub fn new(raw_txn: RawTransaction, authenticator: TransactionAuthenticator) -> Self {
250 Self {
251 raw_txn,
252 authenticator,
253 }
254 }
255
256 #[must_use]
262 pub fn for_simulate_endpoint(&self) -> Self {
263 Self {
264 raw_txn: self.raw_txn.clone(),
265 authenticator: self.authenticator.clone().for_simulate_endpoint(),
266 }
267 }
268
269 pub fn to_bcs(&self) -> AptosResult<Vec<u8>> {
275 aptos_bcs::to_bytes(self).map_err(crate::error::AptosError::bcs)
276 }
277
278 pub fn sender(&self) -> AccountAddress {
280 self.raw_txn.sender
281 }
282
283 pub fn sequence_number(&self) -> u64 {
285 self.raw_txn.sequence_number
286 }
287
288 pub fn hash(&self) -> AptosResult<HashValue> {
294 let bcs_bytes = self.to_bcs()?;
295 let prefix = crate::crypto::sha3_256(b"APTOS::Transaction");
296
297 let mut data = Vec::with_capacity(prefix.len() + 1 + bcs_bytes.len());
298 data.extend_from_slice(&prefix);
299 data.push(0); data.extend_from_slice(&bcs_bytes);
301
302 Ok(HashValue::new(crate::crypto::sha3_256(&data)))
303 }
304
305 pub fn verify_signature(&self) -> AptosResult<()> {
313 match &self.authenticator {
314 #[cfg(feature = "ed25519")]
315 TransactionAuthenticator::Ed25519 {
316 public_key,
317 signature,
318 } => {
319 let public_key = crate::crypto::Ed25519PublicKey::from_bytes(&public_key.0)?;
320 let signature = crate::crypto::Ed25519Signature::from_bytes(&signature.0)?;
321 let signing_message = self.raw_txn.signing_message()?;
322 public_key.verify(&signing_message, &signature)?;
323 if public_key.to_address() != self.raw_txn.sender {
324 return Err(crate::error::AptosError::InvalidSignature(
325 "signed transaction sender does not match authenticator address".into(),
326 ));
327 }
328 Ok(())
329 }
330 #[cfg(not(feature = "ed25519"))]
331 TransactionAuthenticator::Ed25519 { .. } => Err(
332 crate::error::AptosError::FeatureNotEnabled("Ed25519 verification".into()),
333 ),
334 #[cfg(feature = "ed25519")]
335 TransactionAuthenticator::MultiEd25519 {
336 public_key,
337 signature,
338 } => {
339 let public_key = crate::crypto::MultiEd25519PublicKey::from_bytes(public_key)?;
340 let signature = crate::crypto::MultiEd25519Signature::from_bytes(signature)?;
341 let signing_message = self.raw_txn.signing_message()?;
342 public_key.verify(&signing_message, &signature)?;
343 if public_key.to_address() != self.raw_txn.sender {
344 return Err(crate::error::AptosError::InvalidSignature(
345 "signed transaction sender does not match authenticator address".into(),
346 ));
347 }
348 Ok(())
349 }
350 #[cfg(not(feature = "ed25519"))]
351 TransactionAuthenticator::MultiEd25519 { .. } => Err(
352 crate::error::AptosError::FeatureNotEnabled("MultiEd25519 verification".into()),
353 ),
354 TransactionAuthenticator::SingleSender { sender } => {
355 let signing_message = self.raw_txn.signing_message()?;
356 sender.verify(&signing_message)?;
357 if sender.derived_address()? != self.raw_txn.sender {
358 return Err(crate::error::AptosError::InvalidSignature(
359 "signed transaction sender does not match authenticator address".into(),
360 ));
361 }
362 Ok(())
363 }
364 TransactionAuthenticator::MultiAgent {
365 sender,
366 secondary_signer_addresses,
367 secondary_signers,
368 } => {
369 if secondary_signer_addresses.len() != secondary_signers.len() {
370 return Err(crate::error::AptosError::InvalidSignature(
371 "secondary signer count does not match secondary signer addresses".into(),
372 ));
373 }
374 let signing_message = MultiAgentRawTransaction::new(
375 self.raw_txn.clone(),
376 secondary_signer_addresses.clone(),
377 )
378 .signing_message()?;
379 sender.verify(&signing_message)?;
380 if sender.derived_address()? != self.raw_txn.sender {
381 return Err(crate::error::AptosError::InvalidSignature(
382 "signed transaction sender does not match authenticator address".into(),
383 ));
384 }
385 for (expected_address, signer) in secondary_signer_addresses
386 .iter()
387 .zip(secondary_signers.iter())
388 {
389 signer.verify(&signing_message)?;
390 if signer.derived_address()? != *expected_address {
391 return Err(crate::error::AptosError::InvalidSignature(
392 "secondary signer address does not match authenticator address".into(),
393 ));
394 }
395 }
396 Ok(())
397 }
398 TransactionAuthenticator::FeePayer {
399 sender,
400 secondary_signer_addresses,
401 secondary_signers,
402 fee_payer_address,
403 fee_payer_signer,
404 } => {
405 if secondary_signer_addresses.len() != secondary_signers.len() {
406 return Err(crate::error::AptosError::InvalidSignature(
407 "secondary signer count does not match secondary signer addresses".into(),
408 ));
409 }
410 let signing_message = FeePayerRawTransaction::new(
411 self.raw_txn.clone(),
412 secondary_signer_addresses.clone(),
413 *fee_payer_address,
414 )
415 .signing_message()?;
416 sender.verify(&signing_message)?;
417 if sender.derived_address()? != self.raw_txn.sender {
418 return Err(crate::error::AptosError::InvalidSignature(
419 "signed transaction sender does not match authenticator address".into(),
420 ));
421 }
422 for (expected_address, signer) in secondary_signer_addresses
423 .iter()
424 .zip(secondary_signers.iter())
425 {
426 signer.verify(&signing_message)?;
427 if signer.derived_address()? != *expected_address {
428 return Err(crate::error::AptosError::InvalidSignature(
429 "secondary signer address does not match authenticator address".into(),
430 ));
431 }
432 }
433 fee_payer_signer.verify(&signing_message)?;
434 if fee_payer_signer.derived_address()? != *fee_payer_address {
435 return Err(crate::error::AptosError::InvalidSignature(
436 "fee payer address does not match authenticator address".into(),
437 ));
438 }
439 Ok(())
440 }
441 }
442 }
443}
444
445#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
447pub struct TransactionInfo {
448 pub hash: HashValue,
450 #[serde(default)]
452 pub version: Option<u64>,
453 #[serde(default)]
455 pub success: Option<bool>,
456 #[serde(default)]
458 pub vm_status: Option<String>,
459 #[serde(default)]
461 pub gas_used: Option<u64>,
462}
463
464impl TransactionInfo {
465 pub fn is_success(&self) -> bool {
467 self.success.unwrap_or(false)
468 }
469}
470
471#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
473pub struct MultiAgentRawTransaction {
474 pub raw_txn: RawTransaction,
476 pub secondary_signer_addresses: Vec<AccountAddress>,
478}
479
480impl MultiAgentRawTransaction {
481 pub fn new(raw_txn: RawTransaction, secondary_signer_addresses: Vec<AccountAddress>) -> Self {
483 Self {
484 raw_txn,
485 secondary_signer_addresses,
486 }
487 }
488
489 pub fn signing_message(&self) -> AptosResult<Vec<u8>> {
495 #[derive(Serialize)]
497 enum RawTransactionWithData<'a> {
498 MultiAgent {
499 raw_txn: &'a RawTransaction,
500 secondary_signer_addresses: &'a Vec<AccountAddress>,
501 },
502 }
503
504 let prefix = crate::crypto::sha3_256(b"APTOS::RawTransactionWithData");
505
506 let data = RawTransactionWithData::MultiAgent {
507 raw_txn: &self.raw_txn,
508 secondary_signer_addresses: &self.secondary_signer_addresses,
509 };
510
511 let bcs_bytes = aptos_bcs::to_bytes(&data).map_err(crate::error::AptosError::bcs)?;
512
513 let mut message = Vec::with_capacity(prefix.len() + bcs_bytes.len());
514 message.extend_from_slice(&prefix);
515 message.extend_from_slice(&bcs_bytes);
516 Ok(message)
517 }
518}
519
520#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
522pub struct FeePayerRawTransaction {
523 pub raw_txn: RawTransaction,
525 pub secondary_signer_addresses: Vec<AccountAddress>,
527 pub fee_payer_address: AccountAddress,
529}
530
531impl FeePayerRawTransaction {
532 pub fn new(
534 raw_txn: RawTransaction,
535 secondary_signer_addresses: Vec<AccountAddress>,
536 fee_payer_address: AccountAddress,
537 ) -> Self {
538 Self {
539 raw_txn,
540 secondary_signer_addresses,
541 fee_payer_address,
542 }
543 }
544
545 pub fn new_simple(raw_txn: RawTransaction, fee_payer_address: AccountAddress) -> Self {
547 Self {
548 raw_txn,
549 secondary_signer_addresses: vec![],
550 fee_payer_address,
551 }
552 }
553
554 pub fn signing_message(&self) -> AptosResult<Vec<u8>> {
560 #[derive(Serialize)]
561 enum RawTransactionWithData<'a> {
562 #[allow(dead_code)]
563 MultiAgent {
564 raw_txn: &'a RawTransaction,
565 secondary_signer_addresses: &'a Vec<AccountAddress>,
566 },
567 MultiAgentWithFeePayer {
568 raw_txn: &'a RawTransaction,
569 secondary_signer_addresses: &'a Vec<AccountAddress>,
570 fee_payer_address: &'a AccountAddress,
571 },
572 }
573 let prefix = crate::crypto::sha3_256(b"APTOS::RawTransactionWithData");
574
575 let data = RawTransactionWithData::MultiAgentWithFeePayer {
576 raw_txn: &self.raw_txn,
577 secondary_signer_addresses: &self.secondary_signer_addresses,
578 fee_payer_address: &self.fee_payer_address,
579 };
580
581 let bcs_bytes = aptos_bcs::to_bytes(&data).map_err(crate::error::AptosError::bcs)?;
582
583 let mut message = Vec::with_capacity(prefix.len() + bcs_bytes.len());
584 message.extend_from_slice(&prefix);
585 message.extend_from_slice(&bcs_bytes);
586 Ok(message)
587 }
588}
589
590#[cfg(test)]
591mod tests {
592 use super::*;
593 use crate::transaction::payload::EntryFunction;
594 use crate::types::MoveModuleId;
595
596 fn create_test_raw_transaction() -> RawTransaction {
597 RawTransaction::new(
598 AccountAddress::ONE,
599 0,
600 TransactionPayload::EntryFunction(EntryFunction {
601 module: MoveModuleId::from_str_strict("0x1::coin").unwrap(),
602 function: "transfer".to_string(),
603 type_args: vec![],
604 args: vec![],
605 }),
606 100_000,
607 100,
608 1_000_000_000,
609 ChainId::testnet(),
610 )
611 }
612
613 #[cfg(feature = "ed25519")]
614 fn create_transfer_raw_transaction(sender: AccountAddress) -> RawTransaction {
615 RawTransaction::new(
616 sender,
617 0,
618 EntryFunction::apt_transfer(AccountAddress::from_hex("0x2").unwrap(), 1)
619 .unwrap()
620 .into(),
621 100_000,
622 100,
623 1_000_000_000,
624 ChainId::testnet(),
625 )
626 }
627
628 #[test]
629 fn test_raw_transaction_signing_message() {
630 let txn = create_test_raw_transaction();
631 let message = txn.signing_message().unwrap();
632 assert!(!message.is_empty());
633 assert_eq!(message.len(), 32 + txn.to_bcs().unwrap().len());
635 }
636
637 #[test]
638 fn test_raw_transaction_fields() {
639 let txn = create_test_raw_transaction();
640 assert_eq!(txn.sender, AccountAddress::ONE);
641 assert_eq!(txn.sequence_number, 0);
642 assert_eq!(txn.max_gas_amount, 100_000);
643 assert_eq!(txn.gas_unit_price, 100);
644 assert_eq!(txn.expiration_timestamp_secs, 1_000_000_000);
645 assert_eq!(txn.chain_id, ChainId::testnet());
646 }
647
648 #[test]
649 fn test_raw_transaction_bcs_serialization() {
650 let txn = create_test_raw_transaction();
651 let bcs = txn.to_bcs().unwrap();
652 assert!(!bcs.is_empty());
653 }
654
655 #[test]
656 fn test_signed_transaction() {
657 use crate::transaction::authenticator::{Ed25519PublicKey, Ed25519Signature};
658 let txn = create_test_raw_transaction();
659 let auth = crate::transaction::TransactionAuthenticator::Ed25519 {
661 public_key: Ed25519PublicKey([0u8; 32]),
662 signature: Ed25519Signature([0u8; 64]),
663 };
664 let signed = SignedTransaction::new(txn, auth);
665 assert_eq!(signed.sender(), AccountAddress::ONE);
666 }
667
668 #[test]
669 fn test_signed_transaction_bcs() {
670 use crate::transaction::authenticator::{Ed25519PublicKey, Ed25519Signature};
671 let txn = create_test_raw_transaction();
672 let auth = crate::transaction::TransactionAuthenticator::Ed25519 {
673 public_key: Ed25519PublicKey([0u8; 32]),
674 signature: Ed25519Signature([0u8; 64]),
675 };
676 let signed = SignedTransaction::new(txn, auth);
677 let bcs = signed.to_bcs().unwrap();
678 assert!(!bcs.is_empty());
679 }
680
681 #[test]
682 fn test_authenticator_bcs_format() {
683 use crate::transaction::authenticator::{Ed25519PublicKey, Ed25519Signature};
685 let auth = crate::transaction::TransactionAuthenticator::Ed25519 {
686 public_key: Ed25519PublicKey([0xab; 32]),
687 signature: Ed25519Signature([0xcd; 64]),
688 };
689 let bcs = aptos_bcs::to_bytes(&auth).unwrap();
690
691 println!("Authenticator BCS bytes: {}", const_hex::encode(&bcs));
693 println!("First byte (variant index): {}", bcs[0]);
694 println!("Second byte (length prefix): {}", bcs[1]);
695 println!("Third byte (first pubkey byte): {}", bcs[2]);
696
697 assert_eq!(bcs[0], 0, "Ed25519 variant index should be 0");
699 assert_eq!(bcs[1], 32, "Pubkey length prefix should be 32");
701 assert_eq!(bcs[2], 0xab, "First pubkey byte should be 0xab");
703 assert_eq!(bcs[34], 64, "Signature length prefix should be 64");
705 assert_eq!(bcs[35], 0xcd, "First signature byte should be 0xcd");
707 assert_eq!(bcs.len(), 99, "BCS length should be 99");
709 }
710
711 #[test]
712 fn test_transaction_info_deserialization() {
713 let json = r#"{
714 "version": 12345,
715 "hash": "0x0000000000000000000000000000000000000000000000000000000000000001",
716 "gas_used": 100,
717 "success": true,
718 "vm_status": "Executed successfully"
719 }"#;
720 let info: TransactionInfo = serde_json::from_str(json).unwrap();
721 assert_eq!(info.version, Some(12345));
722 assert_eq!(info.gas_used, Some(100));
723 assert_eq!(info.success, Some(true));
724 assert_eq!(info.vm_status, Some("Executed successfully".to_string()));
725 }
726
727 #[test]
728 fn test_fee_payer_raw_transaction_new() {
729 let raw_txn = create_test_raw_transaction();
730 let secondary_addr = AccountAddress::from_hex("0x2").unwrap();
731 let fee_payer_addr = AccountAddress::THREE;
732 let fee_payer = FeePayerRawTransaction::new(raw_txn, vec![secondary_addr], fee_payer_addr);
733 assert_eq!(fee_payer.fee_payer_address, AccountAddress::THREE);
734 assert_eq!(fee_payer.secondary_signer_addresses.len(), 1);
735 }
736
737 #[test]
738 fn test_fee_payer_raw_transaction_new_simple() {
739 let raw_txn = create_test_raw_transaction();
740 let fee_payer = FeePayerRawTransaction::new_simple(raw_txn, AccountAddress::THREE);
741 assert_eq!(fee_payer.fee_payer_address, AccountAddress::THREE);
742 assert!(fee_payer.secondary_signer_addresses.is_empty());
743 }
744
745 #[test]
746 fn test_fee_payer_signing_message() {
747 let raw_txn = create_test_raw_transaction();
748 let fee_payer = FeePayerRawTransaction::new_simple(raw_txn, AccountAddress::THREE);
749 let message = fee_payer.signing_message().unwrap();
750 assert!(!message.is_empty());
751 }
752
753 #[test]
754 fn test_signed_transaction_hash() {
755 use crate::transaction::authenticator::{Ed25519PublicKey, Ed25519Signature};
756 let txn = create_test_raw_transaction();
757 let auth = crate::transaction::TransactionAuthenticator::Ed25519 {
758 public_key: Ed25519PublicKey([0u8; 32]),
759 signature: Ed25519Signature([0u8; 64]),
760 };
761 let signed = SignedTransaction::new(txn, auth);
762 let hash = signed.hash().unwrap();
763 assert_eq!(hash.as_bytes().len(), 32);
765 let hash2 = signed.hash().unwrap();
767 assert_eq!(hash, hash2);
768 }
769
770 #[test]
771 fn test_signed_transaction_sequence_number() {
772 use crate::transaction::authenticator::{Ed25519PublicKey, Ed25519Signature};
773 let txn = create_test_raw_transaction();
774 let auth = crate::transaction::TransactionAuthenticator::Ed25519 {
775 public_key: Ed25519PublicKey([0u8; 32]),
776 signature: Ed25519Signature([0u8; 64]),
777 };
778 let signed = SignedTransaction::new(txn, auth);
779 assert_eq!(signed.sequence_number(), 0);
780 }
781
782 #[test]
783 fn test_transaction_info_is_success() {
784 let info_success = TransactionInfo {
785 hash: HashValue::new([0; 32]),
786 version: Some(1),
787 success: Some(true),
788 vm_status: None,
789 gas_used: Some(100),
790 };
791 assert!(info_success.is_success());
792
793 let info_failed = TransactionInfo {
794 hash: HashValue::new([0; 32]),
795 version: Some(1),
796 success: Some(false),
797 vm_status: Some("Failed".to_string()),
798 gas_used: Some(100),
799 };
800 assert!(!info_failed.is_success());
801
802 let info_unknown = TransactionInfo {
803 hash: HashValue::new([0; 32]),
804 version: None,
805 success: None,
806 vm_status: None,
807 gas_used: None,
808 };
809 assert!(!info_unknown.is_success());
810 }
811
812 #[cfg(feature = "ed25519")]
813 #[test]
814 fn test_verify_signature_ed25519_sender_mismatch() {
815 use crate::account::Ed25519Account;
816 use crate::error::AptosError;
817 use crate::transaction::builder::sign_transaction;
818
819 let signer = Ed25519Account::generate();
820 let claimed_sender = Ed25519Account::generate();
821 let raw_txn = create_transfer_raw_transaction(claimed_sender.address());
822 let signed_txn = sign_transaction(&raw_txn, &signer).unwrap();
823 let err = signed_txn.verify_signature().unwrap_err();
824 assert!(
825 matches!(err, AptosError::InvalidSignature(msg) if msg.contains("sender does not match"))
826 );
827 }
828
829 #[cfg(feature = "ed25519")]
830 #[test]
831 fn test_verify_signature_multi_ed25519_sender_mismatch() {
832 use crate::account::Ed25519Account;
833 use crate::account::MultiEd25519Account;
834 use crate::crypto::Ed25519PrivateKey;
835 use crate::error::AptosError;
836 use crate::transaction::builder::sign_transaction;
837
838 let signer = MultiEd25519Account::new(
839 vec![Ed25519PrivateKey::generate(), Ed25519PrivateKey::generate()],
840 2,
841 )
842 .unwrap();
843 let claimed_sender = Ed25519Account::generate();
844 let raw_txn = create_transfer_raw_transaction(claimed_sender.address());
845 let signed_txn = sign_transaction(&raw_txn, &signer).unwrap();
846 let err = signed_txn.verify_signature().unwrap_err();
847 assert!(
848 matches!(err, AptosError::InvalidSignature(msg) if msg.contains("sender does not match"))
849 );
850 }
851
852 #[cfg(feature = "ed25519")]
853 #[test]
854 fn test_verify_signature_single_sender_sender_mismatch() {
855 use crate::account::Ed25519SingleKeyAccount;
856 use crate::error::AptosError;
857 use crate::transaction::builder::sign_transaction;
858
859 let signer = Ed25519SingleKeyAccount::generate();
860 let claimed_sender = Ed25519SingleKeyAccount::generate();
861 let raw_txn = create_transfer_raw_transaction(claimed_sender.address());
862 let signed_txn = sign_transaction(&raw_txn, &signer).unwrap();
863 let err = signed_txn.verify_signature().unwrap_err();
864 assert!(
865 matches!(err, AptosError::InvalidSignature(msg) if msg.contains("sender does not match"))
866 );
867 }
868
869 #[cfg(feature = "ed25519")]
870 #[test]
871 fn test_verify_signature_multi_agent_sender_mismatch() {
872 use crate::account::{Account, Ed25519Account};
873 use crate::error::AptosError;
874 use crate::transaction::builder::sign_multi_agent_transaction;
875
876 let signer = Ed25519Account::generate();
877 let claimed_sender = Ed25519Account::generate();
878 let secondary = Ed25519Account::generate();
879 let raw_txn = create_transfer_raw_transaction(claimed_sender.address());
880
881 let multi_agent = MultiAgentRawTransaction::new(raw_txn, vec![secondary.address()]);
882 let secondary_refs: Vec<&dyn Account> = vec![&secondary];
883 let signed_txn =
884 sign_multi_agent_transaction(&multi_agent, &signer, &secondary_refs).unwrap();
885 let err = signed_txn.verify_signature().unwrap_err();
886 assert!(
887 matches!(err, AptosError::InvalidSignature(msg) if msg.contains("sender does not match"))
888 );
889 }
890
891 #[cfg(feature = "ed25519")]
892 #[test]
893 fn test_verify_signature_multi_agent_secondary_address_mismatch() {
894 use crate::account::{Account, Ed25519Account};
895 use crate::error::AptosError;
896 use crate::transaction::builder::sign_multi_agent_transaction;
897
898 let sender = Ed25519Account::generate();
899 let expected_secondary = Ed25519Account::generate();
900 let wrong_secondary = Ed25519Account::generate();
901 let raw_txn = create_transfer_raw_transaction(sender.address());
902 let multi_agent =
903 MultiAgentRawTransaction::new(raw_txn, vec![expected_secondary.address()]);
904 let secondary_refs: Vec<&dyn Account> = vec![&wrong_secondary];
905 let signed = sign_multi_agent_transaction(&multi_agent, &sender, &secondary_refs).unwrap();
906 let err = signed.verify_signature().unwrap_err();
907 assert!(matches!(err, AptosError::InvalidSignature(msg) if msg
908 .contains("secondary signer address does not match")));
909 }
910
911 #[cfg(feature = "ed25519")]
912 #[test]
913 fn test_verify_signature_fee_payer_sender_mismatch() {
914 use crate::account::{Account, Ed25519Account};
915 use crate::error::AptosError;
916 use crate::transaction::builder::sign_fee_payer_transaction;
917
918 let signer = Ed25519Account::generate();
919 let claimed_sender = Ed25519Account::generate();
920 let secondary = Ed25519Account::generate();
921 let fee_payer = Ed25519Account::generate();
922 let raw_txn = create_transfer_raw_transaction(claimed_sender.address());
923 let fee_payer_txn =
924 FeePayerRawTransaction::new(raw_txn, vec![secondary.address()], fee_payer.address());
925 let secondary_refs: Vec<&dyn Account> = vec![&secondary];
926 let signed_txn =
927 sign_fee_payer_transaction(&fee_payer_txn, &signer, &secondary_refs, &fee_payer)
928 .unwrap();
929 let err = signed_txn.verify_signature().unwrap_err();
930 assert!(
931 matches!(err, AptosError::InvalidSignature(msg) if msg.contains("sender does not match"))
932 );
933 }
934
935 #[cfg(feature = "ed25519")]
936 #[test]
937 fn test_verify_signature_fee_payer_secondary_address_mismatch() {
938 use crate::account::{Account, Ed25519Account};
939 use crate::error::AptosError;
940 use crate::transaction::builder::sign_fee_payer_transaction;
941
942 let sender = Ed25519Account::generate();
943 let expected_secondary = Ed25519Account::generate();
944 let wrong_secondary = Ed25519Account::generate();
945 let fee_payer = Ed25519Account::generate();
946 let raw_txn = create_transfer_raw_transaction(sender.address());
947 let fee_payer_txn = FeePayerRawTransaction::new(
948 raw_txn,
949 vec![expected_secondary.address()],
950 fee_payer.address(),
951 );
952 let secondary_refs: Vec<&dyn Account> = vec![&wrong_secondary];
953 let signed =
954 sign_fee_payer_transaction(&fee_payer_txn, &sender, &secondary_refs, &fee_payer)
955 .unwrap();
956 let err = signed.verify_signature().unwrap_err();
957 assert!(matches!(err, AptosError::InvalidSignature(msg) if msg
958 .contains("secondary signer address does not match")));
959 }
960
961 #[cfg(feature = "ed25519")]
962 #[test]
963 fn test_verify_signature_fee_payer_address_mismatch() {
964 use crate::account::{Account, Ed25519Account};
965 use crate::error::AptosError;
966 use crate::transaction::authenticator::{AccountAuthenticator, TransactionAuthenticator};
967 use crate::transaction::builder::sign_fee_payer_transaction;
968
969 let sender = Ed25519Account::generate();
970 let secondary = Ed25519Account::generate();
971 let fee_payer = Ed25519Account::generate();
972 let impostor_fee_payer = Ed25519Account::generate();
973 let raw_txn = create_transfer_raw_transaction(sender.address());
974 let fee_payer_txn =
975 FeePayerRawTransaction::new(raw_txn, vec![secondary.address()], fee_payer.address());
976 let secondary_refs: Vec<&dyn Account> = vec![&secondary];
977 let mut signed =
978 sign_fee_payer_transaction(&fee_payer_txn, &sender, &secondary_refs, &fee_payer)
979 .unwrap();
980
981 let signing_message = FeePayerRawTransaction::new(
982 signed.raw_txn.clone(),
983 vec![secondary.address()],
984 fee_payer.address(),
985 )
986 .signing_message()
987 .unwrap();
988 let impostor_auth = AccountAuthenticator::ed25519(
989 impostor_fee_payer.public_key_bytes(),
990 impostor_fee_payer.sign(&signing_message).unwrap(),
991 );
992 if let TransactionAuthenticator::FeePayer {
993 fee_payer_signer, ..
994 } = &mut signed.authenticator
995 {
996 *fee_payer_signer = impostor_auth;
997 } else {
998 panic!("expected FeePayer authenticator");
999 }
1000 let err = signed.verify_signature().unwrap_err();
1001 assert!(
1002 matches!(err, AptosError::InvalidSignature(msg) if msg.contains("fee payer address"))
1003 );
1004 }
1005
1006 fn create_test_orderless_transaction() -> RawTransactionOrderless {
1007 RawTransactionOrderless::with_nonce(
1008 AccountAddress::ONE,
1009 vec![
1010 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
1011 24, 25, 26, 27, 28, 29, 30, 31, 32,
1012 ],
1013 TransactionPayload::EntryFunction(EntryFunction {
1014 module: MoveModuleId::from_str_strict("0x1::coin").unwrap(),
1015 function: "transfer".to_string(),
1016 type_args: vec![],
1017 args: vec![],
1018 }),
1019 100_000,
1020 100,
1021 1_000_000_000,
1022 ChainId::testnet(),
1023 )
1024 }
1025
1026 #[test]
1027 fn test_orderless_transaction_with_nonce() {
1028 let nonce = vec![0xab; 32];
1029 let txn = RawTransactionOrderless::with_nonce(
1030 AccountAddress::ONE,
1031 nonce.clone(),
1032 TransactionPayload::EntryFunction(EntryFunction {
1033 module: MoveModuleId::from_str_strict("0x1::coin").unwrap(),
1034 function: "transfer".to_string(),
1035 type_args: vec![],
1036 args: vec![],
1037 }),
1038 100_000,
1039 100,
1040 1_000_000_000,
1041 ChainId::testnet(),
1042 );
1043 assert_eq!(txn.sender, AccountAddress::ONE);
1044 assert_eq!(txn.nonce, nonce);
1045 assert_eq!(txn.max_gas_amount, 100_000);
1046 assert_eq!(txn.gas_unit_price, 100);
1047 }
1048
1049 #[test]
1050 fn test_orderless_transaction_new_generates_random_nonce() {
1051 let txn1 = RawTransactionOrderless::new(
1052 AccountAddress::ONE,
1053 TransactionPayload::EntryFunction(EntryFunction {
1054 module: MoveModuleId::from_str_strict("0x1::coin").unwrap(),
1055 function: "transfer".to_string(),
1056 type_args: vec![],
1057 args: vec![],
1058 }),
1059 100_000,
1060 100,
1061 1_000_000_000,
1062 ChainId::testnet(),
1063 );
1064 let txn2 = RawTransactionOrderless::new(
1065 AccountAddress::ONE,
1066 TransactionPayload::EntryFunction(EntryFunction {
1067 module: MoveModuleId::from_str_strict("0x1::coin").unwrap(),
1068 function: "transfer".to_string(),
1069 type_args: vec![],
1070 args: vec![],
1071 }),
1072 100_000,
1073 100,
1074 1_000_000_000,
1075 ChainId::testnet(),
1076 );
1077 assert_ne!(txn1.nonce, txn2.nonce);
1079 assert_eq!(txn1.nonce.len(), 32);
1081 assert_eq!(txn2.nonce.len(), 32);
1082 }
1083
1084 #[test]
1085 fn test_orderless_transaction_signing_message() {
1086 let txn = create_test_orderless_transaction();
1087 let message = txn.signing_message().unwrap();
1088 assert!(!message.is_empty());
1089 assert_eq!(message.len(), 32 + txn.to_bcs().unwrap().len());
1091 }
1092
1093 #[test]
1094 fn test_orderless_transaction_bcs() {
1095 let txn = create_test_orderless_transaction();
1096 let bcs = txn.to_bcs().unwrap();
1097 assert!(!bcs.is_empty());
1098 }
1099
1100 #[test]
1101 fn test_signed_orderless_transaction() {
1102 use crate::transaction::authenticator::{Ed25519PublicKey, Ed25519Signature};
1103 let txn = create_test_orderless_transaction();
1104 let auth = crate::transaction::TransactionAuthenticator::Ed25519 {
1105 public_key: Ed25519PublicKey([0u8; 32]),
1106 signature: Ed25519Signature([0u8; 64]),
1107 };
1108 let signed = SignedTransactionOrderless::new(txn, auth);
1109 assert_eq!(signed.sender(), AccountAddress::ONE);
1110 assert_eq!(signed.nonce().len(), 32);
1111 }
1112
1113 #[test]
1114 fn test_signed_orderless_transaction_bcs() {
1115 use crate::transaction::authenticator::{Ed25519PublicKey, Ed25519Signature};
1116 let txn = create_test_orderless_transaction();
1117 let auth = crate::transaction::TransactionAuthenticator::Ed25519 {
1118 public_key: Ed25519PublicKey([0u8; 32]),
1119 signature: Ed25519Signature([0u8; 64]),
1120 };
1121 let signed = SignedTransactionOrderless::new(txn, auth);
1122 let bcs = signed.to_bcs().unwrap();
1123 assert!(!bcs.is_empty());
1124 }
1125
1126 #[test]
1127 fn test_signed_orderless_transaction_hash() {
1128 use crate::transaction::authenticator::{Ed25519PublicKey, Ed25519Signature};
1129 let txn = create_test_orderless_transaction();
1130 let auth = crate::transaction::TransactionAuthenticator::Ed25519 {
1131 public_key: Ed25519PublicKey([0u8; 32]),
1132 signature: Ed25519Signature([0u8; 64]),
1133 };
1134 let signed = SignedTransactionOrderless::new(txn, auth);
1135 let hash = signed.hash().unwrap();
1136 assert_eq!(hash.as_bytes().len(), 32);
1138 let hash2 = signed.hash().unwrap();
1140 assert_eq!(hash, hash2);
1141 }
1142
1143 #[test]
1144 fn test_multi_agent_raw_transaction() {
1145 let raw_txn = create_test_raw_transaction();
1146 let secondary = vec![AccountAddress::from_hex("0x2").unwrap()];
1147 let multi_agent = MultiAgentRawTransaction::new(raw_txn, secondary.clone());
1148 assert_eq!(multi_agent.secondary_signer_addresses, secondary);
1149 }
1150
1151 #[test]
1152 fn test_multi_agent_signing_message() {
1153 let raw_txn = create_test_raw_transaction();
1154 let secondary = vec![AccountAddress::from_hex("0x2").unwrap()];
1155 let multi_agent = MultiAgentRawTransaction::new(raw_txn, secondary);
1156 let message = multi_agent.signing_message().unwrap();
1157 assert!(!message.is_empty());
1158 }
1159}