Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class CoinAddressDerivationTests {
NERVOS -> assertEquals("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3", address)
EVERSCALE -> assertEquals("0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04", address)
TON -> assertEquals("UQDgEMqToTacHic7SnvnPFmvceG5auFkCcAw0mSCvzvKUaT4", address)
APTOS -> assertEquals("0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", address)
APTOS -> assertEquals("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", address)
NEBL -> assertEquals("NgDVaXAwNgBwb88xLiFKomfBmPkEh9F2d7", address)
SUI -> assertEquals("0xada112cfb90b44ba889cc5d39ac2bf46281e4a91f7919c693bcd9b8323e81ed2", address)
HEDERA -> assertEquals("0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5", address)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class CoinAddressDerivationTests {
Nervos -> "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3"
Everscale -> "0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04"
TON -> "UQDgEMqToTacHic7SnvnPFmvceG5auFkCcAw0mSCvzvKUaT4"
Aptos -> "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"
Aptos -> "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"
Nebl -> "NgDVaXAwNgBwb88xLiFKomfBmPkEh9F2d7"
Sui -> "0xada112cfb90b44ba889cc5d39ac2bf46281e4a91f7919c693bcd9b8323e81ed2"
Hedera -> "0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5"
Expand Down
74 changes: 55 additions & 19 deletions rust/chains/tw_aptos/src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,25 @@
// Copyright © 2017 Trust Wallet.

use move_core_types::account_address::{AccountAddress, AccountAddressParseError};
use serde::Serialize;
use std::fmt::{Display, Formatter};
use std::ops::RangeInclusive;
use std::str::FromStr;
use tw_coin_entry::coin_entry::CoinAddress;
use tw_coin_entry::error::prelude::*;
use tw_hash::sha3::sha3_256;
use tw_keypair::ed25519;
use tw_memory::Data;

/// `0x` prefix + 64 hex chars (32 bytes * 2).
const NUM_CHARS: usize = AccountAddress::LENGTH * 2 + 2;
/// There can be up to 10 special addresses in the range of 0x0 to 0xa.
/// https://aptos.dev/network/blockchain/accounts#account-address
const SPECIAL_ADDR_RANGE: RangeInclusive<u8> = 0x0..=0xa;
/// 0x + 1 hex char.
const SPECIAL_ADDR_NUM_CHARS: usize = 3;
const RADIX: u32 = 16;

#[repr(u8)]
pub enum Scheme {
Ed25519 = 0,
Expand Down Expand Up @@ -38,11 +49,22 @@ impl Address {
pub fn inner(&self) -> AccountAddress {
self.addr
}

pub fn is_special_address(&self) -> bool {
let bytes = self.addr.as_ref();

let prefix = &bytes[..bytes.len() - 1];
let last_byte = bytes[bytes.len() - 1];
prefix.iter().all(|&b| b == 0) && SPECIAL_ADDR_RANGE.contains(&last_byte)
}
}

impl Display for Address {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.addr.to_hex_literal())
if self.is_special_address() {
return write!(f, "0x{}", self.addr.short_str_lossless());
}
write!(f, "{:#x}", self.addr)
}
}

Expand All @@ -61,34 +83,48 @@ pub fn from_account_error(_err: AccountAddressParseError) -> AddressError {
impl FromStr for Address {
type Err = AddressError;

// https://github.com/aptos-labs/aptos-core/blob/261019cbdafe1c514c60c2b74357ea2c77d25e67/types/src/account_address.rs#L44
/// In Trust Wallet Core, we only support the removal of zeros for special addresses ranging from 0x0 to 0xa.
/// All other addresses must be 32 bytes (64 hex characters) with required 0x prefix.
/// https://aptos.dev/network/blockchain/accounts#account-address
fn from_str(s: &str) -> Result<Self, Self::Err> {
const NUM_CHARS: usize = AccountAddress::LENGTH * 2;
let mut has_0x = false;
let mut working = s.trim();

// Checks if it has a 0x at the beginning, which is okay
if working.starts_with("0x") {
has_0x = true;
working = &working[2..];
if !s.starts_with("0x") {
return Err(AddressError::MissingPrefix);
}

if working.len() > NUM_CHARS || (!has_0x && working.len() < NUM_CHARS) {
return Err(AddressError::InvalidInput);
if s.len() == SPECIAL_ADDR_NUM_CHARS {
let special_addr =
u8::from_str_radix(&s[2..], RADIX).map_err(|_| AddressError::FromHexError)?;
if !SPECIAL_ADDR_RANGE.contains(&special_addr) {
return Err(AddressError::InvalidInput);
}

let mut bytes = [0u8; AccountAddress::LENGTH];
bytes[AccountAddress::LENGTH - 1] = special_addr;

return Ok(Address {
addr: AccountAddress::from(bytes),
});
}

if !working.chars().all(|c| char::is_ascii_hexdigit(&c)) {
if s.len() != NUM_CHARS {
return Err(AddressError::InvalidInput);
}

let addr = if has_0x {
AccountAddress::from_hex_literal(s.trim())
let addr = AccountAddress::from_hex_literal(s).map_err(from_account_error)?;
Ok(Address { addr })
}
}

impl Serialize for Address {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
serializer.serialize_str(&self.to_string())
} else {
AccountAddress::from_str(s.trim())
self.addr.serialize(serializer)
}
.map_err(from_account_error)?;

Ok(Address { addr })
}
}

Expand Down
52 changes: 25 additions & 27 deletions rust/chains/tw_aptos/src/aptos_move_packages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use std::str::FromStr;

use crate::address::Address;
use crate::transaction_payload::{EntryFunction, TransactionPayload};
use move_core_types::account_address::AccountAddress;
use move_core_types::ident_str;
Expand All @@ -12,10 +13,7 @@ use serde_json::json;
use tw_coin_entry::error::prelude::*;
use tw_encoding::bcs;

pub fn aptos_account_transfer(
to: AccountAddress,
amount: u64,
) -> SigningResult<TransactionPayload> {
pub fn aptos_account_transfer(to: Address, amount: u64) -> SigningResult<TransactionPayload> {
Ok(TransactionPayload::EntryFunction(EntryFunction::new(
ModuleId::new(
AccountAddress::new([
Expand All @@ -27,11 +25,11 @@ pub fn aptos_account_transfer(
ident_str!("transfer").to_owned(),
vec![],
vec![bcs::encode(&to)?, bcs::encode(&amount)?],
json!([to.to_hex_literal(), amount.to_string()]),
json!([to.to_string(), amount.to_string()]),
)))
}

pub fn aptos_account_create_account(auth_key: AccountAddress) -> SigningResult<TransactionPayload> {
pub fn aptos_account_create_account(auth_key: Address) -> SigningResult<TransactionPayload> {
Ok(TransactionPayload::EntryFunction(EntryFunction::new(
ModuleId::new(
AccountAddress::new([
Expand All @@ -43,13 +41,13 @@ pub fn aptos_account_create_account(auth_key: AccountAddress) -> SigningResult<T
ident_str!("create_account").to_owned(),
vec![],
vec![bcs::encode(&auth_key)?],
json!([auth_key.to_hex_literal()]),
json!([auth_key.to_string()]),
)))
}

pub fn coin_transfer(
coin_type: TypeTag,
to: AccountAddress,
to: Address,
amount: u64,
) -> SigningResult<TransactionPayload> {
Ok(TransactionPayload::EntryFunction(EntryFunction::new(
Expand All @@ -63,13 +61,13 @@ pub fn coin_transfer(
ident_str!("transfer").to_owned(),
vec![coin_type],
vec![bcs::encode(&to)?, bcs::encode(&amount)?],
json!([to.to_hex_literal(), amount.to_string()]),
json!([to.to_string(), amount.to_string()]),
)))
}

pub fn aptos_account_transfer_coins(
coin_type: TypeTag,
to: AccountAddress,
to: Address,
amount: u64,
) -> SigningResult<TransactionPayload> {
Ok(TransactionPayload::EntryFunction(EntryFunction::new(
Expand All @@ -83,13 +81,13 @@ pub fn aptos_account_transfer_coins(
ident_str!("transfer_coins").to_owned(),
vec![coin_type],
vec![bcs::encode(&to)?, bcs::encode(&amount)?],
json!([to.to_hex_literal(), amount.to_string()]),
json!([to.to_string(), amount.to_string()]),
)))
}

pub fn token_transfers_offer_script(
receiver: AccountAddress,
creator: AccountAddress,
receiver: Address,
creator: Address,
collection: Vec<u8>,
name: Vec<u8>,
property_version: u64,
Expand All @@ -114,8 +112,8 @@ pub fn token_transfers_offer_script(
bcs::encode(&amount)?,
],
json!([
receiver.to_hex_literal(),
creator.to_hex_literal(),
receiver.to_string(),
creator.to_string(),
String::from_utf8_lossy(&collection),
String::from_utf8_lossy(&name),
property_version.to_string(),
Expand All @@ -125,8 +123,8 @@ pub fn token_transfers_offer_script(
}

pub fn token_transfers_cancel_offer_script(
receiver: AccountAddress,
creator: AccountAddress,
receiver: Address,
creator: Address,
collection: Vec<u8>,
name: Vec<u8>,
property_version: u64,
Expand All @@ -149,8 +147,8 @@ pub fn token_transfers_cancel_offer_script(
bcs::encode(&property_version)?,
],
json!([
receiver.to_hex_literal(),
creator.to_hex_literal(),
receiver.to_string(),
creator.to_string(),
String::from_utf8_lossy(&collection),
String::from_utf8_lossy(&name),
property_version.to_string()
Expand All @@ -159,8 +157,8 @@ pub fn token_transfers_cancel_offer_script(
}

pub fn token_transfers_claim_script(
sender: AccountAddress,
creator: AccountAddress,
sender: Address,
creator: Address,
collection: Vec<u8>,
name: Vec<u8>,
property_version: u64,
Expand All @@ -183,8 +181,8 @@ pub fn token_transfers_claim_script(
bcs::encode(&property_version)?,
],
json!([
sender.to_hex_literal(),
creator.to_hex_literal(),
sender.to_string(),
creator.to_string(),
String::from_utf8_lossy(&collection),
String::from_utf8_lossy(&name),
property_version.to_string()
Expand All @@ -193,8 +191,8 @@ pub fn token_transfers_claim_script(
}

pub fn fungible_asset_transfer(
metadata_address: AccountAddress,
to: AccountAddress,
metadata_address: Address,
to: Address,
amount: u64,
) -> SigningResult<TransactionPayload> {
Ok(TransactionPayload::EntryFunction(EntryFunction::new(
Expand All @@ -214,8 +212,8 @@ pub fn fungible_asset_transfer(
bcs::encode(&amount)?,
],
json!([
metadata_address.to_hex_literal(),
to.to_hex_literal(),
metadata_address.to_string(),
to.to_string(),
amount.to_string()
]),
)))
Expand Down
43 changes: 0 additions & 43 deletions rust/chains/tw_aptos/src/aptos_move_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@ impl From<Address> for AccountAddress {
}
}

impl From<&Address> for AccountAddress {
fn from(address: &Address) -> Self {
address.0
}
}

/// A wrapper of a Move identifier
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct IdentifierWrapper(pub Identifier);
Expand All @@ -53,12 +47,6 @@ impl From<Identifier> for IdentifierWrapper {
}
}

impl From<&Identifier> for IdentifierWrapper {
fn from(value: &Identifier) -> IdentifierWrapper {
Self(value.clone())
}
}

/// A Move struct tag for referencing an onchain struct type
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MoveStructTag {
Expand All @@ -80,17 +68,6 @@ impl From<StructTag> for MoveStructTag {
}
}

impl From<&StructTag> for MoveStructTag {
fn from(tag: &StructTag) -> Self {
Self {
address: tag.address.into(),
module: IdentifierWrapper::from(&tag.module),
name: IdentifierWrapper::from(&tag.name),
generic_type_params: tag.type_params.iter().map(MoveType::from).collect(),
}
}
}

impl TryFrom<MoveStructTag> for StructTag {
type Error = EncodingError;

Expand Down Expand Up @@ -197,26 +174,6 @@ impl From<TypeTag> for MoveType {
}
}

impl From<&TypeTag> for MoveType {
fn from(tag: &TypeTag) -> Self {
match tag {
TypeTag::Bool => MoveType::Bool,
TypeTag::U8 => MoveType::U8,
TypeTag::U16 => MoveType::U16,
TypeTag::U32 => MoveType::U32,
TypeTag::U64 => MoveType::U64,
TypeTag::U128 => MoveType::U128,
TypeTag::U256 => MoveType::U256,
TypeTag::Address => MoveType::Address,
TypeTag::Signer => MoveType::Signer,
TypeTag::Vector(v) => MoveType::Vector {
items: Box::new(MoveType::from(v.as_ref())),
},
TypeTag::Struct(v) => MoveType::Struct((&**v).into()),
}
}
}

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

Expand Down
4 changes: 2 additions & 2 deletions rust/chains/tw_aptos/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl Compiler {
.into_tw()
.context("Invalid sender address")?;
let signed_tx = builder
.sender(sender.inner())
.sender(sender)
.sequence_number(input.sequence_number as u64)
.build()?
.pre_image()?;
Expand Down Expand Up @@ -61,7 +61,7 @@ impl Compiler {
.or_tw_err(SigningErrorType::Error_signatures_count)?;

let signed_tx = builder
.sender(sender.inner())
.sender(sender)
.sequence_number(input.sequence_number as u64)
.build()?
.compile(signature.to_vec(), public_key.to_vec())?;
Expand Down
Loading
Loading