diff --git a/rust/tw_aptos/src/address.rs b/rust/tw_aptos/src/address.rs index 2de65e751ea..a1c20b50171 100644 --- a/rust/tw_aptos/src/address.rs +++ b/rust/tw_aptos/src/address.rs @@ -8,11 +8,27 @@ use std::fmt::{Display, Formatter}; use std::str::FromStr; use move_core_types::account_address::{AccountAddress, AccountAddressParseError}; use tw_coin_entry::coin_entry::CoinAddress; -use tw_coin_entry::error::AddressError; +use tw_coin_entry::error::{AddressError, AddressResult}; use tw_keypair::ed25519; use tw_memory::Data; use tw_hash::sha3::sha3_256; + +pub trait AptosAddress: FromStr + Into
{ + /// Tries to parse an address from the string representation. + /// Returns `Ok(None)` if the given `s` string is empty. + #[inline] + fn from_str_optional(s: &str) -> AddressResult> { + if s.is_empty() { + return Ok(None); + } + + Self::from_str(s).map(Some) + } +} + +impl AptosAddress for Address {} + #[repr(u8)] pub enum Scheme { Ed25519 = 0, diff --git a/rust/tw_aptos/src/entry.rs b/rust/tw_aptos/src/entry.rs index bec0919da03..6665d526772 100644 --- a/rust/tw_aptos/src/entry.rs +++ b/rust/tw_aptos/src/entry.rs @@ -19,6 +19,7 @@ use tw_keypair::ed25519::sha512::KeyPair; use tw_proto::Aptos::Proto; use tw_proto::TxCompiler::Proto as CompilerProto; use crate::address::Address; +use crate::signer::{AptosContext, Signer, StandardAptosContext}; use crate::transaction_builder; @@ -61,11 +62,7 @@ impl CoinEntry for AptosEntry { #[inline] fn sign(&self, _coin: &dyn CoinContext, input: Self::SigningInput<'_>) -> Self::SigningOutput { - let mut builder = transaction_builder::TransactionFactory::new_from_protobuf(input.clone()); - let sender = Address::from_str(&input.sender).unwrap().inner(); - let key_pair = KeyPair::try_from(input.private_key.to_vec().as_slice()).unwrap(); - let raw_tx = builder.sender(sender).sequence_number(input.sequence_number as u64).build().sign(key_pair).unwrap(); - todo!() + Signer::::sign_proto(input) } #[inline] diff --git a/rust/tw_aptos/src/lib.rs b/rust/tw_aptos/src/lib.rs index 960516c0b16..b3235f83aac 100644 --- a/rust/tw_aptos/src/lib.rs +++ b/rust/tw_aptos/src/lib.rs @@ -9,6 +9,8 @@ pub mod address; pub mod aptos_move_packages; pub mod constants; pub mod entry; + +pub mod signer; pub mod transaction; pub mod transaction_builder; pub mod transaction_payload; diff --git a/rust/tw_aptos/src/signer.rs b/rust/tw_aptos/src/signer.rs new file mode 100644 index 00000000000..a9d017ad720 --- /dev/null +++ b/rust/tw_aptos/src/signer.rs @@ -0,0 +1,48 @@ +use std::borrow::Cow; +use std::marker::PhantomData; +use std::str::FromStr; +use tw_coin_entry::error::SigningResult; +use tw_coin_entry::signing_output_error; +use tw_keypair::ed25519; +use tw_proto::Aptos::Proto; +use tw_proto::Aptos::Proto::TransactionAuthenticator; +use crate::address::{Address, AptosAddress}; +use crate::transaction_builder; + +pub trait AptosContext { + type Address: AptosAddress; +} + +#[derive(Default)] +pub struct StandardAptosContext; + +impl AptosContext for StandardAptosContext { + type Address = Address; +} + +pub struct Signer { + _phantom: PhantomData, +} + +impl Signer { + #[inline] + pub fn sign_proto(input: Proto::SigningInput<'_>) -> Proto::SigningOutput<'static> { + Self::sign_proto_impl(input) + .unwrap_or_else(|e| signing_output_error!(Proto::SigningOutput, e)) + } + + fn sign_proto_impl( + input: Proto::SigningInput<'_>, + ) -> SigningResult> { + let key_pair = ed25519::sha512::KeyPair::try_from(input.private_key.as_ref())?; + let mut builder = transaction_builder::TransactionFactory::new_from_protobuf(input.clone()); + let sender = Address::from_str(&input.sender)?; + let raw_tx = builder.sender(sender.inner()).sequence_number(input.sequence_number as u64).build().sign(key_pair)?; + Ok(Proto::SigningOutput { + raw_txn: raw_tx.raw_txn_bytes().clone().into(), + encoded: raw_tx.encoded().clone().into(), + authenticator: Some((*raw_tx.authenticator()).clone().into()), + ..Proto::SigningOutput::default() + }) + } +} \ No newline at end of file diff --git a/rust/tw_aptos/src/transaction.rs b/rust/tw_aptos/src/transaction.rs index c3b200781e7..5058a35254b 100644 --- a/rust/tw_aptos/src/transaction.rs +++ b/rust/tw_aptos/src/transaction.rs @@ -4,11 +4,14 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +use std::borrow::Cow; use move_core_types::account_address::AccountAddress; use serde::Serialize; +use tw_coin_entry::error::SigningResult; use tw_keypair::ed25519::sha512::{KeyPair, PublicKey}; use tw_keypair::traits::{KeyPairTrait, SigningKeyTrait}; use tw_number::Sign; +use tw_proto::Aptos::Proto; use crate::transaction_payload::{EntryFunction, TransactionPayload}; #[derive(Clone, Serialize)] @@ -20,10 +23,23 @@ pub enum TransactionAuthenticator { } } +impl From for Proto::TransactionAuthenticator<'_> { + fn from(from: TransactionAuthenticator) -> Self { + Proto::TransactionAuthenticator { + signature: Cow::from(from.get_signature()), + public_key: Cow::from(from.get_public_key()), + } + } +} + impl TransactionAuthenticator { pub fn get_signature(&self) -> Vec { match self { TransactionAuthenticator::Ed25519 { public_key: _public_key, signature } => { signature.clone() } } } + + pub fn get_public_key(&self) -> Vec { + match self { TransactionAuthenticator::Ed25519 { public_key, signature: _signature } => { public_key.clone() } } + } } /// RawTransaction is the portion of a transaction that a client signs. @@ -105,7 +121,7 @@ impl RawTransaction { pub fn sign( self, key_pair: KeyPair, - ) -> Result { + ) -> SigningResult { let mut serialized = bcs::to_bytes(&self).unwrap(); let mut to_sign = tw_hash::sha3::sha3_256("APTOS::RawTransaction".as_bytes()); to_sign.extend_from_slice(serialized.as_slice());