From c35a4e31cca0694eb18db3d3b87b0e63569afdbc Mon Sep 17 00:00:00 2001 From: BigtoC Date: Sun, 20 Jul 2025 14:55:06 +0800 Subject: [PATCH] feat(wallet): Add Ethereum address conversion to Bech32 format --- lib/application/wallet/utils.dart | 52 +++++++++++++++++++++++++ lib/application/wallet/wallet_bloc.dart | 9 +++++ 2 files changed, 61 insertions(+) create mode 100644 lib/application/wallet/utils.dart diff --git a/lib/application/wallet/utils.dart b/lib/application/wallet/utils.dart new file mode 100644 index 0000000..c4cf029 --- /dev/null +++ b/lib/application/wallet/utils.dart @@ -0,0 +1,52 @@ +import "package:blockchain_utils/bech32/bech32_base.dart"; +import "package:blockchain_utils/bip/address/addr_dec_utils.dart"; +import "package:blockchain_utils/bip/address/eth_addr.dart"; +import "package:blockchain_utils/bip/coin_conf/constant/coins_conf.dart"; +import "package:blockchain_utils/hex/hex.dart"; + +class EthBech32Converter { + /// Encodes an Ethereum address in Bech32 format. + /// This method takes a hexadecimal Ethereum address and a prefix, + /// converts the address to bytes, and then encodes to Bech32-format address. + /// + /// Parameters: + /// - hexAddress: The hexadecimal representation of the Ethereum address. + /// - prefix: The Bech32 prefix to be used for encoding. + /// + /// Returns: + /// A Bech32-encoded address. + /// + /// Throws: + /// - AssertionError: If the length of the cleaned hexadecimal address is not equal to the expected Ethereum address length. + static String ethAddressToBech32(String ethAddress, prefix) { + + final cleanHex = AddrDecUtils.validateAndRemovePrefix( + ethAddress, CoinsConf.ethereum.params.addrPrefix! + ); + assert( + cleanHex.length == EthAddrConst.addrLen, + "Invalid Ethereum address length: ${cleanHex.length}, expected: ${EthAddrConst.addrLen}" + ); + final hexAddressBytes = hex.decode(cleanHex); + return Bech32Encoder.encode(prefix, hexAddressBytes); + } + + /// Decodes a Bech32-encoded address. + /// This method takes a Bech32-encoded address + /// and decodes it to its hexadecimal representation. + /// + /// Parameters: + /// - bech32Address: The Bech32-encoded Ethereum address. + /// + /// Returns: + /// A string representing the Ethereum address. + static String bech32ToEthAddress(String bech32Address, prefix) { + final decoded = Bech32Decoder.decode(prefix, bech32Address); + final hexEncoded = hex.encode(decoded); + assert( + hexEncoded.length == EthAddrConst.addrLen, + "Invalid Ethereum address length: ${hexEncoded.length}, expected: ${EthAddrConst.addrLen}" + ); + return "${CoinsConf.ethereum.params.addrPrefix!}$hexEncoded"; + } +} diff --git a/lib/application/wallet/wallet_bloc.dart b/lib/application/wallet/wallet_bloc.dart index 899b900..8717f3a 100644 --- a/lib/application/wallet/wallet_bloc.dart +++ b/lib/application/wallet/wallet_bloc.dart @@ -1,5 +1,7 @@ import "package:cosmos_sdk/cosmos_sdk.dart"; +import "package:hnotes/application/wallet/utils.dart"; import "package:hnotes/infrastructure/blockchain/wallet_repository.dart"; +import "package:hnotes/infrastructure/constants.dart"; import "package:hnotes/infrastructure/local_storage/secrets/secrets_repository.dart"; import "package:rxdart/rxdart.dart"; @@ -40,6 +42,13 @@ class WalletBloc { String receiver, {TransactionConfirmationCallback? confirmTransaction} ) async { + if (receiver.startsWith("0x")) { + receiver = EthBech32Converter.ethAddressToBech32( + receiver, + chainAddressPrefix + ); + } + final message = MsgSend( fromAddress: CosmosBaseAddress(sender), toAddress: CosmosBaseAddress(receiver),