Skip to content

Commit

Permalink
Addresses review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
gupnik committed Jan 2, 2025
1 parent 63097f2 commit a2c369b
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 100 deletions.
1 change: 0 additions & 1 deletion rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion rust/chains/tw_aptos/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1"
serde_json = "1.0"
tw_coin_entry = { path = "../../tw_coin_entry" }
tw_encoding = { path = "../../tw_encoding" }
Expand Down
81 changes: 5 additions & 76 deletions rust/chains/tw_aptos/src/aptos_move_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,9 @@
//
// Copyright © 2017 Trust Wallet.

use anyhow::format_err;
use move_core_types::{language_storage::TypeTag, parser::parse_type_tag};
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::str::FromStr;
use tw_encoding::hex;

/// Hex encoded bytes to allow for having bytes represented in JSON
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HexEncodedBytes(pub Vec<u8>);

impl HexEncodedBytes {
pub fn json(&self) -> anyhow::Result<serde_json::Value> {
Ok(serde_json::to_value(self)?)
}
}

impl FromStr for HexEncodedBytes {
type Err = anyhow::Error;

fn from_str(s: &str) -> anyhow::Result<Self, anyhow::Error> {
let hex_str = if let Some(hex) = s.strip_prefix("0x") {
hex
} else {
s
};
Ok(Self(hex::decode(hex_str).map_err(|e| {
format_err!(
"decode hex-encoded string({:?}) failed, caused by error: {}",
s,
e
)
})?))
}
}

impl fmt::Display for HexEncodedBytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "0x{}", hex::encode(&self.0, false))?;
Ok(())
}
}

impl Serialize for HexEncodedBytes {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.to_string().serialize(serializer)
}
}

impl<'de> Deserialize<'de> for HexEncodedBytes {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = <String>::deserialize(deserializer)?;
s.parse().map_err(D::Error::custom)
}
}

impl From<Vec<u8>> for HexEncodedBytes {
fn from(bytes: Vec<u8>) -> Self {
Self(bytes)
}
}

impl From<HexEncodedBytes> for Vec<u8> {
fn from(bytes: HexEncodedBytes) -> Self {
bytes.0
}
}
use tw_encoding::EncodingError;

/// An enum of Move's possible types on-chain
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -105,7 +37,7 @@ pub enum MoveType {
}

impl FromStr for MoveType {
type Err = anyhow::Error;
type Err = EncodingError;

fn from_str(mut s: &str) -> Result<Self, Self::Err> {
let mut is_ref = false;
Expand Down Expand Up @@ -175,9 +107,9 @@ impl From<&TypeTag> for MoveType {
}

impl TryFrom<MoveType> for TypeTag {
type Error = anyhow::Error;
type Error = EncodingError;

fn try_from(tag: MoveType) -> anyhow::Result<Self> {
fn try_from(tag: MoveType) -> Result<Self, Self::Error> {
let ret = match tag {
MoveType::Bool => TypeTag::Bool,
MoveType::U8 => TypeTag::U8,
Expand All @@ -189,10 +121,7 @@ impl TryFrom<MoveType> for TypeTag {
MoveType::Address => TypeTag::Address,
MoveType::Vector { items } => TypeTag::Vector(Box::new((*items).try_into()?)),
_ => {
return Err(anyhow::anyhow!(
"Invalid move type for converting into `TypeTag`: {:?}",
&tag
))
return Err(EncodingError::InvalidInput);
},
};
Ok(ret)
Expand Down
2 changes: 1 addition & 1 deletion rust/chains/tw_aptos/src/transaction_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ impl TransactionFactory {
let abi =
serde_json::from_str::<Value>(&input.abi).unwrap_or(serde_json::json!([]));
if is_blind_sign {
let entry_function = EntryFunction::try_from((v, abi))?;
let entry_function = EntryFunction::parse_with_abi(v, abi)?;
Ok(factory.payload(TransactionPayload::EntryFunction(entry_function)))
} else {
SigningError::err(SigningErrorType::Error_input_parse)
Expand Down
76 changes: 56 additions & 20 deletions rust/chains/tw_aptos/src/transaction_payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// Copyright © 2017 Trust Wallet.

use crate::aptos_move_types::{HexEncodedBytes, MoveType};
use crate::aptos_move_types::MoveType;
use crate::serde_helper::vec_bytes;
use move_core_types::account_address::AccountAddress;
use move_core_types::identifier::Identifier;
Expand All @@ -15,6 +15,7 @@ use serde_json::{json, Value};
use std::default::Default;
use std::str::FromStr;
use tw_coin_entry::error::prelude::*;
use tw_encoding::hex::DecodeHex;
use tw_encoding::{bcs, EncodingError, EncodingResult};
use tw_memory::Data;
use tw_proto::Aptos;
Expand Down Expand Up @@ -56,10 +57,16 @@ pub struct EntryFunction {
json_args: Value,
}

impl TryFrom<(Value, Value)> for EntryFunction {
impl TryFrom<Value> for EntryFunction {
type Error = EntryFunctionError;

fn try_from((value, abi): (Value, Value)) -> EntryFunctionResult<Self> {
fn try_from(value: Value) -> EntryFunctionResult<Self> {
Self::parse_with_abi(value, json!([]))
}
}

impl EntryFunction {
pub fn parse_with_abi(value: Value, abi: Value) -> EntryFunctionResult<Self> {
let function_str = value["function"]
.as_str()
.ok_or(EntryFunctionError::MissingFunctionName)?;
Expand Down Expand Up @@ -115,38 +122,67 @@ impl TryFrom<(Value, Value)> for EntryFunction {
}
}

fn parse_argument(val: &str, abi_str: &str) -> anyhow::Result<TransactionArgument> {
let move_type: MoveType = abi_str.parse::<MoveType>()?;
fn parse_argument(val: &str, abi_str: &str) -> EncodingResult<TransactionArgument> {
let move_type: MoveType = abi_str
.parse::<MoveType>()
.map_err(|_| EncodingError::InvalidInput)?;
Ok(match move_type {
MoveType::Bool => TransactionArgument::Bool(val.parse::<bool>()?),
MoveType::U8 => TransactionArgument::U8(val.parse::<u8>()?),
MoveType::U16 => TransactionArgument::U16(val.parse::<u16>()?),
MoveType::U32 => TransactionArgument::U32(val.parse::<u32>()?),
MoveType::U64 => TransactionArgument::U64(val.parse::<u64>()?),
MoveType::U128 => TransactionArgument::U128(val.parse::<u128>()?),
MoveType::U256 => TransactionArgument::U256(val.parse::<u256::U256>()?),
MoveType::Address => TransactionArgument::Address(AccountAddress::from_hex_literal(val)?),
MoveType::Bool => TransactionArgument::Bool(
val.parse::<bool>()
.map_err(|_| EncodingError::InvalidInput)?,
),
MoveType::U8 => {
TransactionArgument::U8(val.parse::<u8>().map_err(|_| EncodingError::InvalidInput)?)
},
MoveType::U16 => TransactionArgument::U16(
val.parse::<u16>()
.map_err(|_| EncodingError::InvalidInput)?,
),
MoveType::U32 => TransactionArgument::U32(
val.parse::<u32>()
.map_err(|_| EncodingError::InvalidInput)?,
),
MoveType::U64 => TransactionArgument::U64(
val.parse::<u64>()
.map_err(|_| EncodingError::InvalidInput)?,
),
MoveType::U128 => TransactionArgument::U128(
val.parse::<u128>()
.map_err(|_| EncodingError::InvalidInput)?,
),
MoveType::U256 => TransactionArgument::U256(
val.parse::<u256::U256>()
.map_err(|_| EncodingError::InvalidInput)?,
),
MoveType::Address => TransactionArgument::Address(
AccountAddress::from_hex_literal(val).map_err(|_| EncodingError::InvalidInput)?,
),
MoveType::Vector { items } => parse_vector_argument(val, items)?,
_ => {
anyhow::bail!("unexpected move type {:?} for value {:?}", move_type, val)
return Err(EncodingError::InvalidInput);
},
})
}

fn parse_vector_argument(val: &str, layout: Box<MoveType>) -> anyhow::Result<TransactionArgument> {
let val = serde_json::to_value(val)?;
fn parse_vector_argument(
val_str: &str,
layout: Box<MoveType>,
) -> EncodingResult<TransactionArgument> {
let val = serde_json::to_value(val_str).map_err(|_| EncodingError::InvalidInput)?;
if matches!(*layout, MoveType::U8) {
Ok(TransactionArgument::U8Vector(
serde_json::from_value::<HexEncodedBytes>(val)?.into(),
val_str
.decode_hex()
.map_err(|_| EncodingError::InvalidInput)?,
))
} else if let Value::Array(list) = val {
let vals = list
.into_iter()
.map(|v| serde_json::from_value::<u8>(v).map_err(|_| anyhow::anyhow!("expected u8")))
.collect::<anyhow::Result<_>>()?;
.map(|v| serde_json::from_value::<u8>(v).map_err(|_| EncodingError::InvalidInput))
.collect::<EncodingResult<_>>()?;
Ok(TransactionArgument::U8Vector(vals))
} else {
anyhow::bail!("expected vector<{:?}>, but got: {:?}", layout, val)
return Err(EncodingError::InvalidInput);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/proto/Aptos.proto
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ message SigningInput {
TokenTransferCoinsMessage token_transfer_coins = 15;
}

optional string abi = 16;
optional string abi = 21;
}

// Information related to the signed transaction
Expand Down

0 comments on commit a2c369b

Please sign in to comment.