diff --git a/packages/core/src/scanning.ts b/packages/core/src/scanning.ts index 1a76122..74ca324 100644 --- a/packages/core/src/scanning.ts +++ b/packages/core/src/scanning.ts @@ -120,15 +120,11 @@ export const scanOutputsWithTweak = ( const matches = new Map(); let n = 0; let counterIncrement = 0; - const typedScanTweak = new Uint8Array(scanTweak); - if ( - typedScanTweak.length === 33 && - (typedScanTweak[0] === 0x02 || typedScanTweak[0] === 0x03) - ) { + if (scanTweak.length === 33) { // Use publicKeyTweakMul for compressed pubkey const ecdhSecret = secp256k1.publicKeyTweakMul( - typedScanTweak, + scanTweak, scanPrivateKey, true, ); @@ -146,28 +142,9 @@ export const scanOutputsWithTweak = ( ); n += counterIncrement; } while (counterIncrement > 0 && outputs.length > 0); - } else if (typedScanTweak.length === 32) { - const ecdhSecret = secp256k1.privateKeyTweakMul( - scanPrivateKey, - typedScanTweak, - ); - do { - const tweak = createTaggedHash( - 'BIP0352/SharedSecret', - Buffer.concat([ecdhSecret, serialiseUint32(n)]), - ); - counterIncrement = processTweak( - spendPublicKey, - tweak, - outputs, - matches, - labels, - ); - n += counterIncrement; - } while (counterIncrement > 0 && outputs.length > 0); } else { throw new Error( - `Expected scanTweak to be either 32 bytes or a 33-byte compressed public key, got ${typedScanTweak.length}`, + `Expected scanTweak to be either 33-byte compressed public key, got ${scanTweak.length}`, ); } diff --git a/packages/core/test/scanning.spec.ts b/packages/core/test/scanning.spec.ts index 0621382..bec30e0 100644 --- a/packages/core/test/scanning.spec.ts +++ b/packages/core/test/scanning.spec.ts @@ -1,4 +1,4 @@ -import { LabelMap, scanOutputs } from '../src'; +import { LabelMap, scanOutputs, scanOutputsWithTweak } from '../src'; import { Buffer } from 'buffer'; import { testData } from './fixtures/scanning'; @@ -33,4 +33,41 @@ describe('Scanning', () => { ); }, ); + + it('should scan using tweak', async () => { + const scanPrivateKey = Buffer.from( + '38658693c017c46fd6b8bb94b8766c123cd5baf6026338305b6f59f82b36f9c0', + 'hex', + ); + const spendPublicKey = Buffer.from( + '02833085c9a716d36b467552c00d6aa8bd42e39adbe98b05bc203110177192f702', + 'hex', + ); + const tweak = Buffer.from( + '02ccd442a997b40661a9a1e233884986a9c970f5da3b68514c6ea2533b708e2ae1', + 'hex', + ); + const outputs = [ + Buffer.from( + '025a90a5fad7ab4d32e41fd02de786f7af3ecbe85bd18784e51e89a97c8693ca3c', + 'hex', + ), + ]; + const expectedTweakHex = + '635aaddb7a1f7f64a6b78ddf47772ae987f6e29b79bb4eebbf1826f21af25e39'; + + const res = scanOutputsWithTweak( + scanPrivateKey, + spendPublicKey, + tweak, + outputs, + ); + + expect(res).toBeDefined(); + expect(res.size).toBeGreaterThan(0); + + const [[output, foundTweak]] = Array.from(res); + expect(output.toString()).toBe(outputs[0].toString()); + expect(foundTweak.toString()).toBe(expectedTweakHex); + }); }); diff --git a/packages/wallet/src/wallet.ts b/packages/wallet/src/wallet.ts index f0c3269..2ec42f3 100644 --- a/packages/wallet/src/wallet.ts +++ b/packages/wallet/src/wallet.ts @@ -342,19 +342,15 @@ export class Wallet { const matchedUTXOs: Coin[] = []; for (const transaction of silentBlock.transactions) { - console.log('Processing transaction:', transaction.txid); - console.log('Outputs:', transaction.outputs); - const outputs = transaction.outputs; - + if (outputs.length === 0) continue; - + const outputPubKeys = outputs.map((output) => - Buffer.from(output.pubKey, 'hex'), - ); - + Buffer.from('02' + output.pubKey, 'hex'), + ); + const scanTweak = Buffer.from(transaction.scanTweak, 'hex'); - console.log('scanTweak:', scanTweak.toString('hex')); const matches = scanOutputsWithTweak( scanPrivateKey, @@ -362,13 +358,12 @@ export class Wallet { scanTweak, outputPubKeys, ); - console.log('Matches found:', Array.from(matches.keys())); if (matches.size === 0) continue; for (const pubKeyHex of matches.keys()) { const output = outputs.find( - (output) => output.pubKey === pubKeyHex, + (output) => output.pubKey === pubKeyHex.slice(2), ); if (output) { matchedUTXOs.push( diff --git a/packages/wallet/test/helpers/silent-block.fixtures.ts b/packages/wallet/test/helpers/silent-block.fixtures.ts new file mode 100644 index 0000000..e94fa54 --- /dev/null +++ b/packages/wallet/test/helpers/silent-block.fixtures.ts @@ -0,0 +1,17 @@ +export const parsedSilentBlock = { + type: 0, + transactions: [ + { + txid: '7d77c249a6ade81248e1a2ba28e1128e3beee0a3727d6cc0b1bed13e07f12147', + scanTweak: + '02ccd442a997b40661a9a1e233884986a9c970f5da3b68514c6ea2533b708e2ae1', + outputs: [ + { + pubKey: '5a90a5fad7ab4d32e41fd02de786f7af3ecbe85bd18784e51e89a97c8693ca3c', + value: 4000000, + vout: 0, + }, + ], + }, + ], +}; diff --git a/packages/wallet/test/wallet.spec.ts b/packages/wallet/test/wallet.spec.ts index 4cd8e1f..2aa21b7 100644 --- a/packages/wallet/test/wallet.spec.ts +++ b/packages/wallet/test/wallet.spec.ts @@ -3,55 +3,7 @@ import { BitcoinRpcClient } from './helpers/bitcoin-rpc-client'; import { Wallet } from '../src'; import { WalletDB } from '@silent-pay/level/src'; import { EsploraClient } from '@silent-pay/esplora/src'; -// import { silentBlock } from '@silent-pay/core/test/fixtures/encoding.ts'; - -const silentBlock = [ - { - parsedBlock: { - type: 0, - transactions: [ - { - txid: 'd60cdcc1bdb78d44bf83e2ae0efa94bbb1187ba2397e4a40960d853b78e15b4f', - scanTweak: - '0381a4ef11a26108cf10d8c33305b77aec009beed82a77bb47b716a04ae9ae5bf1', - outputs: [ - { - pubKey: 'ca80a975d09b84b385e39d779293121b9a7c80942d824d2496f098e3f077ced3', - value: 24771038, - vout: 1, - }, - ], - }, - { - txid: 'cf655a07ed9b672ecf811ce8b3b69257eecaf0518edd025d7014d7c0177050cb', - scanTweak: - '03d87550a4ba8ed7dd37df7739a021d6d212e70e8a8e6e9e70249c13a11fd9f412', - outputs: [ - { - pubKey: '5af9436eb515871413a913f24290ba003eab7a64b9c62cb72051599a383de8ff', - value: 26940, - vout: 0, - }, - { - pubKey: 'e7a3ab33572f47b074878c749a5f9a5d7e026f10b6ffcab1388e9356c07828fa', - value: 4400, - vout: 1, - }, - ], - }, - ], - }, - encodedBlockHex: - '0002d60cdcc1bdb78d44bf83e2ae0efa94bbb1187ba2397e4a40960d853b78e15b4f01000000000179f9deca80a975d09b84b385e39d779293121b9a7c80942d824d2496f098e3f077ced3000000010381a4ef11a26108cf10d8c33305b77aec009beed82a77bb47b716a04ae9ae5bf1cf655a07ed9b672ecf811ce8b3b69257eecaf0518edd025d7014d7c0177050cb02000000000000693c5af9436eb515871413a913f24290ba003eab7a64b9c62cb72051599a383de8ff000000000000000000001130e7a3ab33572f47b074878c749a5f9a5d7e026f10b6ffcab1388e9356c07828fa0000000103d87550a4ba8ed7dd37df7739a021d6d212e70e8a8e6e9e70249c13a11fd9f412', - }, - { - parsedBlock: { - type: 0, - transactions: [], - }, - encodedBlockHex: '0000', - }, -]; +import { parsedSilentBlock } from './helpers/silent-block.fixtures'; describe('Wallet', () => { let wallet: Wallet; @@ -212,7 +164,7 @@ describe('Wallet', () => { throw new Error('Scan private key is undefined'); const matchedUTXOs = wallet.matchSilentBlockOutputs( - silentBlock[0].parsedBlock, + parsedSilentBlock, scanKey.privateKey, scanKey.publicKey, spendKey.publicKey, @@ -222,28 +174,13 @@ describe('Wallet', () => { }); it('should scan a silent block and update UTXOs', async () => { - if (!silentBlock || !silentBlock[0]) { - throw new Error('Silent block fixture is not properly defined'); - } - - const block = silentBlock[0].parsedBlock; - - await wallet.scanSilentBlock(block); + await wallet.scanSilentBlock(parsedSilentBlock); const utxos = await walletDB.getUnspentCoins(); expect(utxos).toContainEqual( expect.objectContaining({ - txid: 'd60cdcc1bdb78d44bf83e2ae0efa94bbb1187ba2397e4a40960d853b78e15b4f', - vout: 1, - value: 24771038, - address: expect.any(String), - status: { isConfirmed: true }, - }), - ); - expect(utxos).toContainEqual( - expect.objectContaining({ - txid: 'cf655a07ed9b672ecf811ce8b3b69257eecaf0518edd025d7014d7c0177050cb', + txid: '7d77c249a6ade81248e1a2ba28e1128e3beee0a3727d6cc0b1bed13e07f12147', vout: 0, - value: 26940, + value: 4000000, address: expect.any(String), status: { isConfirmed: true }, }),