Skip to content

fix(aptos): Enforce address hex representation length to 32 bytes except special address#4730

Open
sergei-boiko-trustwallet wants to merge 3 commits intomasterfrom
fix/aptos-tighten-address-format
Open

fix(aptos): Enforce address hex representation length to 32 bytes except special address#4730
sergei-boiko-trustwallet wants to merge 3 commits intomasterfrom
fix/aptos-tighten-address-format

Conversation

@sergei-boiko-trustwallet
Copy link
Copy Markdown
Contributor

@sergei-boiko-trustwallet sergei-boiko-trustwallet commented Apr 9, 2026

Aptos — Stricter Address Format

The Aptos address format is now strictly validated to conform with the official Aptos address specification.

Why this change matters

Aptos addresses are 32 bytes long, while Ethereum addresses are 20 bytes. Before this fix, Trust Wallet Core accepted Aptos addresses without leading zeros — e.g. 0x7968dab…3f30 (63 hex chars).
This meant a 20-byte Ethereum address could be silently accepted as a valid Aptos address by prepending 12 zero bytes (24 leading hex zeros).
A user could therefore accidentally send Aptos funds to what looks like an Aptos address, but is really an Ethereum address with padded zeros — funds that would be permanently lost with no way to recover them.
Enforcing the full 32-byte (64 hex char) representation closes this attack surface.


Breaking change 1 — Address input format

Any Aptos address passed to the library (as sender, to, auth_key, receiver, creator, smart_contract_address, metadata_address, etc. in SigningInput or related messages) must now be one of:

  • A special address: 0x0 through 0xa (short form, exactly 3 characters including the 0x prefix).
  • A full 32-byte address: 0x prefix followed by exactly 64 hex characters (no more, no less). All leading zeros must be present.

Previously, the 0x prefix was optional and addresses shorter than 64 hex chars were silently accepted. Both of these are now rejected.

Example Before After
0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30 ✅ valid ✅ valid
0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30 ✅ valid (63 hex chars) rejected (missing leading zero)
7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30 ✅ valid (no prefix) rejected (missing 0x prefix)
0x1 ✅ valid ✅ valid (special address)
0xb ✅ valid rejected (0xb is not a special address)

Action required: Ensure all Aptos addresses your app reads from user input, QR codes, deep links, or external APIs include the 0x prefix and the full 64 hex characters with leading zeros before passing them to Trust Wallet Core.


Breaking change 2 — Address display output

Addresses returned by Trust Wallet Core (e.g. from key derivation, TWAnyAddress, JSON signing output) will now always include leading zeros, producing a full 64 hex character address.

  • Old output: 0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30
  • New output: 0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30

Special addresses (0x00xa) are not affected and continue to be displayed in their short form.

Action required: Update any hardcoded address strings, UI snapshots, or test fixtures that rely on the old trimmed representation. To automatically re-derive and update all stored Aptos addresses in a TWStoredKey wallet, call:

TWStoredKeyFixAddresses(storedKey, password)

This will re-generate the correct 64-char address for every Aptos account in the keystore without requiring the user to re-import their wallet.


Breaking change 3 — Blind signing (SigningInput.any_encoded)

The any_encoded field in SigningInput is used for smart-contract and dApp blind-signing flows. The raw hex-encoded transaction inside any_encoded may contain embedded Aptos addresses. Those addresses are now validated with the same strict rules above.

If a dApp constructs a transaction that contains a short-form address (e.g. 0x7968dab… with only 63 hex chars), the signing request will fail and return an error instead of producing a signature.

Impact: Some dApps that generate transactions with non-padded addresses may stop working for Trust Wallet users until the dApp is updated to emit fully-padded 64-char Aptos addresses.

Action required (dApp integrators): Ensure all Aptos addresses embedded in serialised transactions passed via any_encoded conform to the new format (64 hex chars with 0x prefix, or a valid special address 0x00xa).

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR standardizes Aptos address handling across tw_aptos by introducing/propagating a custom Address type with stricter parsing and normalized formatting rules (full 32-byte hex for most addresses; short form only for special 0x0..=0xa).

Changes:

  • Implemented stricter Aptos Address parsing/formatting/serialization rules, including special-address short form handling.
  • Propagated the new Address type through transaction building/signing and related modules (NFT, liquid staking, move package helpers).
  • Updated Aptos tests and golden JSON fixtures to reflect enforced 32-byte hex formatting.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
rust/chains/tw_aptos/src/address.rs Adds strict address parsing rules + special-address formatting and custom Serialize.
rust/chains/tw_aptos/src/transaction.rs Switches raw transaction sender from AccountAddress to Address and updates JSON output formatting.
rust/chains/tw_aptos/src/transaction_payload.rs Parses Move address arguments via the new Address parser (then converts to AccountAddress).
rust/chains/tw_aptos/src/transaction_builder.rs Updates builder/factory APIs to accept/store Address consistently.
rust/chains/tw_aptos/src/signer.rs Passes Address directly into the transaction builder.
rust/chains/tw_aptos/src/compiler.rs Passes Address directly into the transaction builder for compilation paths.
rust/chains/tw_aptos/src/nft.rs Migrates NFT ops address fields/serialization to Address + new string formatting.
rust/chains/tw_aptos/src/liquid_staking.rs Migrates liquid staking addresses to Address, converting to inner AccountAddress only where required by Move types.
rust/chains/tw_aptos/src/aptos_move_packages.rs Updates Move package helper APIs to take Address and uses normalized string formatting in JSON args.
rust/chains/tw_aptos/src/aptos_move_types.rs Removes now-unneeded From<&...> impls after refactor.
rust/chains/tw_aptos/tests/signer.rs Updates test vectors to use enforced 32-byte hex formatting and new Address type.
rust/tw_tests/tests/chains/aptos/aptos_address.rs Expands normalization/valid/invalid coverage for special vs non-special addresses and strict prefix/length rules.
rust/tw_tests/tests/chains/aptos/test_cases.rs Updates golden JSON fixture addresses to include required leading zero.
rust/coverage.stats Updates coverage baseline.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 9, 2026

Binary size comparison

➡️ aarch64-apple-ios:

- 14.34 MB
+ 14.34 MB 	 -2 KB

➡️ aarch64-apple-ios-sim:

- 14.34 MB
+ 14.34 MB 	 -1 KB

➡️ aarch64-linux-android:

- 18.77 MB
+ 18.77 MB 	 -3 KB

➡️ armv7-linux-androideabi:

- 16.20 MB
+ 16.20 MB 	 -2 KB

➡️ wasm32-unknown-emscripten:

- 13.68 MB
+ 13.68 MB 	 +1 KB

Copy link
Copy Markdown

@nikhil-gupta-tw nikhil-gupta-tw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants