From e372ee74f1951e84a6fc4e3e3673ad7b4faa82e4 Mon Sep 17 00:00:00 2001 From: DXC Development Date: Thu, 17 Sep 2026 20:33:09 +0700 Subject: [PATCH] test: lock XEC addresses to ecash/ectest prefixes Asserts that livenet XEC addresses are encoded with the ecash: prefix, testnet with ectest:, that generated addresses never contain bitcoincash, and that a valid legacy bitcoincash-prefixed cashaddr still decodes to the same script (paste-in compatibility only). The prefix participates in the cashaddr checksum, so the legacy vector is re-encoded rather than prefix-swapped. --- .../src/__tests__/crypto.test.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/abcpay-wallet-core/src/__tests__/crypto.test.ts b/packages/abcpay-wallet-core/src/__tests__/crypto.test.ts index 3567153..1ed1a0e 100644 --- a/packages/abcpay-wallet-core/src/__tests__/crypto.test.ts +++ b/packages/abcpay-wallet-core/src/__tests__/crypto.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; +import { encodeCashAddress } from 'ecashaddrjs'; import { assembleTxHex, computeMaxSend, @@ -81,6 +82,33 @@ describe('addresses', () => { ); }); + it('encodes XEC addresses with ecash/ectest prefixes only', () => { + const creds = createCredentials({ coin: 'xec', mnemonic: MNEMONIC }); + const livenet = deriveWalletAddress({ + coin: 'xec', + xPubKeys: [creds.xPubKey], + m: 1, + n: 1, + path: relativePath(false, 0) + }); + const testnet = deriveWalletAddress({ + coin: 'xec', + network: 'testnet', + xPubKeys: [creds.xPubKey], + m: 1, + n: 1, + path: relativePath(false, 0) + }); + expect(livenet.address.startsWith('ecash:')).toBe(true); + expect(testnet.address.startsWith('ectest:')).toBe(true); + expect(livenet.address.includes('bitcoincash')).toBe(false); + + // Legacy bitcoincash-prefixed input is tolerated for paste-in compatibility only. + const decoded = decodeAddress('xec', livenet.address); + const legacyBch = encodeCashAddress('bitcoincash', decoded.type, decoded.hashHex); + expect(decodeAddress('xec', legacyBch).hashHex).toBe(decoded.hashHex); + }); + it('builds the same P2SH address regardless of copayer xpub order', () => { const a = createCredentials({ coin: 'xec', mnemonic: MNEMONIC, isMultisig: true }); const b = createCredentials({