import { describe, expect, it } from 'vitest'; import { HDKey } from '@scure/bip32'; import { hdKeyToAccount } from 'viem/accounts'; import { assertPublicOnly, deriveBaseAddress, deriveTronAddress, isValidBaseAddress, isValidTronAddress, } from '../src/derivation'; // Deterministic test root (fixed seed — test fixture only, controls no real funds). const seed = new Uint8Array(64).fill(7); const root = HDKey.fromMasterSeed(seed); const account = root.derive("m/44'/60'/0'"); const xpub = account.publicExtendedKey; describe('deriveBaseAddress', () => { it('matches viem HD account derivation at m/0/i for the same root', () => { for (const i of [0, 1, 7]) { const expected = hdKeyToAccount(root, { path: `m/44'/60'/0'/0/${i}` }).address; expect(deriveBaseAddress(xpub, i)).toBe(expected); } }); it('produces checksummed, distinct addresses per index', () => { const a0 = deriveBaseAddress(xpub, 0); const a1 = deriveBaseAddress(xpub, 1); expect(a0).not.toBe(a1); expect(isValidBaseAddress(a0)).toBe(true); expect(a0).toMatch(/^0x[0-9a-fA-F]{40}$/); }); }); describe('deriveTronAddress', () => { it('produces valid base58check Tron addresses (T…) that differ per index', () => { const t0 = deriveTronAddress(xpub, 0); const t1 = deriveTronAddress(xpub, 1); expect(t0.startsWith('T')).toBe(true); expect(t0).not.toBe(t1); expect(isValidTronAddress(t0)).toBe(true); expect(isValidTronAddress(t1)).toBe(true); }); it('is deterministic', () => { expect(deriveTronAddress(xpub, 3)).toBe(deriveTronAddress(xpub, 3)); }); }); describe('non-custodial tripwire', () => { it('refuses extended spending keys outright', () => { const xprv = account.privateExtendedKey; expect(() => assertPublicOnly(xprv)).toThrow(/can never spend/); expect(() => deriveBaseAddress(xprv, 0)).toThrow(/can never spend/); }); it('rejects unknown key prefixes and out-of-range indexes', () => { expect(() => deriveBaseAddress('zpub123', 0)).toThrow(/unsupported/); expect(() => deriveBaseAddress(xpub, -1)).toThrow(/out of range/); expect(() => deriveBaseAddress(xpub, 2 ** 31)).toThrow(/out of range/); }); }); describe('address validation', () => { it('accepts known-good and rejects junk', () => { expect(isValidTronAddress('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t')).toBe(true); expect(isValidTronAddress('not-an-address')).toBe(false); expect(isValidBaseAddress('0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913')).toBe(true); expect(isValidBaseAddress('0x123')).toBe(false); }); });