// // BitcoinTests.swift // OS Vault // // Author: Simon-Pierre Boucher // Mail: contact@spboucher.ai // import XCTest import BitcoinDevKit @testable import OSVaultKit final class BitcoinTests: XCTestCase { // Official BIP-84 test vector (public, not a real wallet): the // all-"abandon" mnemonic must derive these first addresses at m/84'/0'/0'. let vectorMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" func testBIP84VectorFirstAddress() throws { let (external, internalD) = try BitcoinService.secretDescriptors( mnemonic: vectorMnemonic, network: .mainnet) let wallet = try Wallet(descriptor: external, changeDescriptor: internalD, network: .bitcoin, persister: Persister.newInMemory()) let first = wallet.revealNextAddress(keychain: .external) XCTAssertEqual(first.address.description, "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu") let second = wallet.revealNextAddress(keychain: .external) XCTAssertEqual(second.address.description, "bc1qnjg0jd8228aq7egyzacy8cys3knf9xvrerkf9g") let change = wallet.revealNextAddress(keychain: .internal) XCTAssertEqual(change.address.description, "bc1q8c6fshw2dlwun7ekn9qwf37cu2rn755upcp6el") } func testPublicDescriptorsAreWatchOnly() throws { let (external, _) = try BitcoinService.publicDescriptors( mnemonic: vectorMnemonic, network: .mainnet) // A public descriptor must not contain private key material. XCTAssertFalse(external.description.contains("xprv")) XCTAssertTrue(external.description.contains("xpub")) } func testAddressValidationPerNetwork() { XCTAssertTrue(BitcoinService.validate( address: "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", network: .mainnet)) XCTAssertFalse(BitcoinService.validate( address: "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", network: .signet)) XCTAssertFalse(BitcoinService.validate(address: "not-an-address", network: .mainnet)) XCTAssertFalse(BitcoinService.validate( address: "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", network: .mainnet)) } func testBTCAmountParsing() { XCTAssertEqual(BitcoinService.parseBTC("1"), 100_000_000) XCTAssertEqual(BitcoinService.parseBTC("0.00000001"), 1) XCTAssertNil(BitcoinService.parseBTC("0.000000001")) // sub-sat XCTAssertEqual(BitcoinService.formatBTC(150_000_000), "1.5") XCTAssertEqual(BitcoinService.formatBTC(1), "0.00000001") } }