Skip to content

Commit 2e2335d

Browse files
feat(abstract-utxo): improve Litecoin address conversion for cross-chain recovery
Use WASM-based address conversion for more robust handling of P2SH addresses between Litecoin and Bitcoin networks. The new implementation correctly converts both mainnet (M→3) and testnet (Q→2) address formats. Co-authored-by: llm-git <llm-git@ttll.de> Issue: BTC-2891
1 parent c908b56 commit 2e2335d

1 file changed

Lines changed: 9 additions & 23 deletions

File tree

modules/abstract-utxo/src/recovery/crossChainRecovery.ts

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,9 @@ export async function isWalletAddress(wallet: IWallet | WalletV1, address: strin
114114
}
115115

116116
/**
117-
* Convert a Litecoin P2SH address from M... format (scriptHash 0x32) to the legacy 3... format (scriptHash 0x05).
118-
* This is needed for cross-chain recovery when LTC was sent to a BTC address, because the BTC wallet
117+
* Convert a Litecoin P2SH address from M... format (scriptHash 0x32) to the legacy 3... format (scriptHash 0x05)
118+
* and Q... format (scriptHash 0x32) to the legacy 2... format (scriptHash 0x05).
119+
* This is needed for cross-chain recovery when (T)LTC was sent to a (T)BTC address, because the (T)BTC wallet
119120
* stores addresses in the 3... format while the LTC blockchain returns addresses in M... format.
120121
*
121122
* @param address - LTC address to convert
@@ -127,30 +128,15 @@ export function convertLtcAddressToLegacyFormat(address: string, coinName: UtxoC
127128
return address;
128129
}
129130

130-
const network = getNetworkFromCoinName(coinName);
131-
try {
132-
// Try to decode as bech32 - these don't need conversion
133-
utxolib.address.fromBech32(address);
131+
// only consider addresses that start with M or Q (modern ltc p2sh prefixes)
132+
if (!address.startsWith('M') && !address.startsWith('Q')) {
134133
return address;
135-
} catch (e) {
136-
// Not bech32, continue to base58
137134
}
138135

139-
try {
140-
const decoded = utxolib.address.fromBase58Check(address, network);
141-
// Only convert P2SH addresses (scriptHash), not P2PKH (pubKeyHash)
142-
if (decoded.version === network.scriptHash) {
143-
// Convert to legacy format using Bitcoin's scriptHash (0x05)
144-
const legacyScriptHash =
145-
coinName === 'ltc' ? utxolib.networks.bitcoin.scriptHash : utxolib.networks.testnet.scriptHash;
146-
return utxolib.address.toBase58Check(decoded.hash, legacyScriptHash, network);
147-
}
148-
// P2PKH or other - return unchanged
149-
return address;
150-
} catch (e) {
151-
// If decoding fails, return the original address
152-
return address;
153-
}
136+
const scriptPubKey = wasmAddress.toOutputScriptWithCoin(address, coinName);
137+
const dstCoin = coinName === 'ltc' ? 'btc' : 'tbtc';
138+
const dstAddress = wasmAddress.fromOutputScriptWithCoin(scriptPubKey, dstCoin);
139+
return dstAddress;
154140
}
155141

156142
/**

0 commit comments

Comments
 (0)