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