diff --git a/tests/mocks/constants.ts b/tests/mocks/constants.ts index 9c3da76..3b5bc48 100644 --- a/tests/mocks/constants.ts +++ b/tests/mocks/constants.ts @@ -48,3 +48,30 @@ export const TEST_REGTEST_ATTESTOR_APIS = [ ]; export const TEST_REGTEST_ATTESTOR_EXTENDED_GROUP_PUBLIC_KEY = 'tpubDDqN2CmTDKaGeqXMayfCZEvjZqntifi4r1ztmRWsGuE1VE4bosR3mBKQwVaCxZcmg8R1nHDMDzDmzjoccBMgwZV1hhz51tAXVnhjABCQcwA'; + +export const TEST_DEPOSIT_PSBT_PARTIALLY_SIGNED_DEPOSIT_PSBT_1 = + '70736274ff0100c5020000000269680a0f87525a598abaf823342a4cb6d632027252e51d242e51c61770f17c990200000000f0ffffff751757d16e395a1da0457531b8a9eed579bdd87f3d60034b179976be5fb5178a0100000000ffffffff0370170000000000001600145a81f36535980769bccc23c196337a78458abd1e80969800000000002251203789ed985ab9d1c94f5889973376a88d9940835206461151685a7a3fbb84de599ec6202901000000160014add70fb03578d3ac85aab80897395bb046223c92000000000001011f302b6d2901000000160014add70fb03578d3ac85aab80897395bb046223c92220202f4d8696f9b275f4e10af63f03bcb7fbba7b1ed44dd9b12a973c8d20212beb8d1483045022100d7788684a0d1f05f35a861f72457a8d1aa7efbfdf1227d3e6cdf72b7feab9f7e02203d57106adbaf190731c0447e990833835c6de86052161e39b06193ad306e80a1010001012b404b4c00000000002251203789ed985ab9d1c94f5889973376a88d9940835206461151685a7a3fbb84de594114bb7e175e63064479102ee0b69a719a9f54f8f1b29df17cfaa5437697393e7cfce24db130ab82d20d322c295aa18921a7fe87fb13df3d5b3b2ee0469e2a84511440d8fb920db7745d01f2762b6285e10a3d16ef056fd1dc26879eea5dc5410d4da53a458820088e5a22c11ef27527a8db546a0e8997d80b4b3c4f861a6b4410bd482215c1e52a5f154612da28faade658332157966492aa20a523162a8b584682a23dc72645205216652630455eb8546bbab45e6fdef6498eee683ed339f405d326414b05b192ad20bb7e175e63064479102ee0b69a719a9f54f8f1b29df17cfaa5437697393e7cfcacc0011720e52a5f154612da28faade658332157966492aa20a523162a8b584682a23dc726011820e24db130ab82d20d322c295aa18921a7fe87fb13df3d5b3b2ee0469e2a84511400000000'; + +export const TEST_WITHDRAW_PSBT_PARTIALLY_SIGNED_WITHDRAW_PSBT_1 = + '70736274ff01009c0200000001acf3a308a937ebcc2464fa33f99f1197145b49a7124a72f5511666649d3236030000000000f0ffffff034c1d0000000000001600145a81f36535980769bccc23c196337a78458abd1e404b4c00000000002251203789ed985ab9d1c94f5889973376a88d9940835206461151685a7a3fbb84de599a2c4c0000000000160014add70fb03578d3ac85aab80897395bb046223c92000000000001012b80969800000000002251203789ed985ab9d1c94f5889973376a88d9940835206461151685a7a3fbb84de594114bb7e175e63064479102ee0b69a719a9f54f8f1b29df17cfaa5437697393e7cfce24db130ab82d20d322c295aa18921a7fe87fb13df3d5b3b2ee0469e2a84511440525267fb9b7ea3797aad490251906662f24599c086733a95f33aa1c25c6e47d408d58c8be7a56edb491d56741744e85b746366f9175754f053a7703e69f6ab392215c1e52a5f154612da28faade658332157966492aa20a523162a8b584682a23dc72645205216652630455eb8546bbab45e6fdef6498eee683ed339f405d326414b05b192ad20bb7e175e63064479102ee0b69a719a9f54f8f1b29df17cfaa5437697393e7cfcacc0011720e52a5f154612da28faade658332157966492aa20a523162a8b584682a23dc726011820e24db130ab82d20d322c295aa18921a7fe87fb13df3d5b3b2ee0469e2a84511400000000'; + +export const TEST_DEPOSIT_PSBT_PARTIALLY_SIGNED_DEPOSIT_PSBT_2 = + '70736274ff0100d1020000000266916a1f40ca9c611a60002f81854402ffb424e457c1c23931d06267cf5bc8950000000000f0ffffff8f5413dcad4cbe8876459a1b1fe1817a94206f0d0bbb79765403438c3bb07dbe0100000000ffffffff0370170000000000001600145a81f36535980769bccc23c196337a78458abd1e8096980000000000225120b033a3d9562d22aa4a5476ae9cb6a5858b0959e084b49a3fd92edfba87e8254faa59f42400000000225120676504fcaf89119cc9762c2f867aaa56aa3fffc85158f7dd61da345cdbf4a9be000000000001012b40be402500000000225120676504fcaf89119cc9762c2f867aaa56aa3fffc85158f7dd61da345cdbf4a9be011340fd74c7650cb7edb0eea5fca080ac7dea90ab23ecf616eac1ad4a263d75fcf3940d3c7c09512369cb39a473e4eb1249204df36115095dc2849556686b9087824e011720bb7e175e63064479102ee0b69a719a9f54f8f1b29df17cfaa5437697393e7cfc0001012b404b4c0000000000225120b033a3d9562d22aa4a5476ae9cb6a5858b0959e084b49a3fd92edfba87e8254f4114bb7e175e63064479102ee0b69a719a9f54f8f1b29df17cfaa5437697393e7cfce24db130ab82d20d322c295aa18921a7fe87fb13df3d5b3b2ee0469e2a845114404387a71d8174f9c42ef8ce8cbe0c88c01863fb80ea796955f6678b95a7ae7e07dd1559688bee882feefdda2e98880ea6e6ba886c438bdb2188b41f4f68d09f992215c01fba2e8661f2ed0a747d76578d3a6508a31879569d97da86a0a207c2538ebaa445205216652630455eb8546bbab45e6fdef6498eee683ed339f405d326414b05b192ad20bb7e175e63064479102ee0b69a719a9f54f8f1b29df17cfaa5437697393e7cfcacc00117201fba2e8661f2ed0a747d76578d3a6508a31879569d97da86a0a207c2538ebaa4011820e24db130ab82d20d322c295aa18921a7fe87fb13df3d5b3b2ee0469e2a84511400000000'; + +export const TEST_WITHDRAW_PSBT_PARTIALLY_SIGNED_WITHDRAW_PSBT_2 = + '70736274ff0100a80200000001b2097c129d74fc6e80d673ba3a83e4858c046444993991cad52f66d28ff65b970000000000f0ffffff034c1d0000000000001600145a81f36535980769bccc23c196337a78458abd1e404b4c0000000000225120b033a3d9562d22aa4a5476ae9cb6a5858b0959e084b49a3fd92edfba87e8254f822c4c0000000000225120676504fcaf89119cc9762c2f867aaa56aa3fffc85158f7dd61da345cdbf4a9be000000000001012b8096980000000000225120b033a3d9562d22aa4a5476ae9cb6a5858b0959e084b49a3fd92edfba87e8254f4114bb7e175e63064479102ee0b69a719a9f54f8f1b29df17cfaa5437697393e7cfce24db130ab82d20d322c295aa18921a7fe87fb13df3d5b3b2ee0469e2a84511440c06edfdd88bc66ffec4c8ff30fd3f6b38e25ebd85c09635a7b1594f66af614ba320c4d98e1c6017f38c8d752227ca24a5cd178cb462a4444c465fc773738e4b52215c01fba2e8661f2ed0a747d76578d3a6508a31879569d97da86a0a207c2538ebaa445205216652630455eb8546bbab45e6fdef6498eee683ed339f405d326414b05b192ad20bb7e175e63064479102ee0b69a719a9f54f8f1b29df17cfaa5437697393e7cfcacc00117201fba2e8661f2ed0a747d76578d3a6508a31879569d97da86a0a207c2538ebaa4011820e24db130ab82d20d322c295aa18921a7fe87fb13df3d5b3b2ee0469e2a84511400000000'; + +export const TEST_ALICE_NATIVE_SEGWIT_PAYMENT_SCRIPT_1 = + '0014add70fb03578d3ac85aab80897395bb046223c92'; + +export const TEST_ALICE_NATIVE_SEGWIT_PUBLIC_KEY_1 = + '02f4d8696f9b275f4e10af63f03bcb7fbba7b1ed44dd9b12a973c8d20212beb8d1'; + +export const TEST_ALICE_NATIVE_SEGWIT_PUBLIC_KEY_2 = + '0385c8f8844b7c197b96d933b01b2b82b97b9f9d55c81947e1db5cfb3de375508b'; + +export const TEST_ALICE_TAPROOT_PUBLIC_KEY_1 = + '03bb7e175e63064479102ee0b69a719a9f54f8f1b29df17cfaa5437697393e7cfc'; + +export const TEST_ALICE_TAPROOT_PUBLIC_KEY_2 = + '03940f5559dc92a3253e8699e9c632badfe5c2b1a13a113b85022d30cdab9c0ed8'; diff --git a/tests/unit/bitcoin-functions.test.ts b/tests/unit/bitcoin-functions.test.ts new file mode 100644 index 0000000..974c8f5 --- /dev/null +++ b/tests/unit/bitcoin-functions.test.ts @@ -0,0 +1,103 @@ +import { hexToBytes } from '@noble/hashes/utils'; +import { Transaction, p2tr, p2wpkh } from '@scure/btc-signer'; +import { regtest } from 'bitcoinjs-lib/src/networks'; + +import { + ecdsaPublicKeyToSchnorr, + finalizeUserInputs, + getInputIndicesByScript, +} from '../../src/functions/bitcoin/bitcoin-functions'; +import { + TEST_ALICE_NATIVE_SEGWIT_PAYMENT_SCRIPT_1, + TEST_ALICE_NATIVE_SEGWIT_PUBLIC_KEY_1, + TEST_ALICE_NATIVE_SEGWIT_PUBLIC_KEY_2, + TEST_ALICE_TAPROOT_PUBLIC_KEY_1, + TEST_ALICE_TAPROOT_PUBLIC_KEY_2, + TEST_DEPOSIT_PSBT_PARTIALLY_SIGNED_DEPOSIT_PSBT_1, + TEST_DEPOSIT_PSBT_PARTIALLY_SIGNED_DEPOSIT_PSBT_2, + TEST_WITHDRAW_PSBT_PARTIALLY_SIGNED_WITHDRAW_PSBT_1, +} from '../mocks/constants'; + +describe('Bitcoin Functions', () => { + describe('getInputIndicesByScript', () => { + it('correctly retrieves the input indices by script', () => { + const transaction = Transaction.fromPSBT( + hexToBytes(TEST_DEPOSIT_PSBT_PARTIALLY_SIGNED_DEPOSIT_PSBT_1) + ); + const aliceScript = hexToBytes(TEST_ALICE_NATIVE_SEGWIT_PAYMENT_SCRIPT_1); + const inputIndices = getInputIndicesByScript(aliceScript, transaction); + expect(inputIndices).toEqual([0]); + }); + + it('correctly retrieve an empty array when the script is not found', () => { + const transaction = Transaction.fromPSBT( + hexToBytes(TEST_WITHDRAW_PSBT_PARTIALLY_SIGNED_WITHDRAW_PSBT_1) + ); + const aliceScript = hexToBytes(TEST_ALICE_NATIVE_SEGWIT_PAYMENT_SCRIPT_1); + const inputIndices = getInputIndicesByScript(aliceScript, transaction); + expect(inputIndices).toEqual([]); + }); + }); + + describe('finalizeUserInputs', () => { + it('correctly finalizes inputs given a transaction and a native segwit payment script', () => { + const transaction = Transaction.fromPSBT( + hexToBytes(TEST_DEPOSIT_PSBT_PARTIALLY_SIGNED_DEPOSIT_PSBT_1) + ); + + const alicePublicKey = Buffer.from(TEST_ALICE_NATIVE_SEGWIT_PUBLIC_KEY_1, 'hex'); + const alicePayment = p2wpkh(alicePublicKey, regtest); + + finalizeUserInputs(transaction, alicePayment); + + expect(transaction.getInput(0).finalScriptWitness).toBeDefined(); + expect(transaction.getInput(1).finalScriptWitness).toBeUndefined(); + }); + + it('does not finalize inputs given a transaction and a native segwit payment script', () => { + const transaction = Transaction.fromPSBT( + hexToBytes(TEST_DEPOSIT_PSBT_PARTIALLY_SIGNED_DEPOSIT_PSBT_1) + ); + + const alicePublicKey = Buffer.from(TEST_ALICE_NATIVE_SEGWIT_PUBLIC_KEY_2, 'hex'); + const alicePayment = p2wpkh(alicePublicKey, regtest); + + finalizeUserInputs(transaction, alicePayment); + + expect(transaction.getInput(0).finalScriptWitness).toBeUndefined(); + expect(transaction.getInput(1).finalScriptWitness).toBeUndefined(); + }); + }); + + it('correctly finalizes inputs given a transaction and a taproot payment script', () => { + const transaction = Transaction.fromPSBT( + hexToBytes(TEST_DEPOSIT_PSBT_PARTIALLY_SIGNED_DEPOSIT_PSBT_2) + ); + + const alicePublicKey = ecdsaPublicKeyToSchnorr( + Buffer.from(TEST_ALICE_TAPROOT_PUBLIC_KEY_1, 'hex') + ); + const alicePayment = p2tr(alicePublicKey, undefined, regtest); + + finalizeUserInputs(transaction, alicePayment); + + expect(transaction.getInput(0).finalScriptWitness).toBeDefined(); + expect(transaction.getInput(1).finalScriptWitness).toBeUndefined(); + }); + + it('does not finalize inputs given a transaction and a taproot payment script', () => { + const transaction = Transaction.fromPSBT( + hexToBytes(TEST_DEPOSIT_PSBT_PARTIALLY_SIGNED_DEPOSIT_PSBT_2) + ); + + const alicePublicKey = ecdsaPublicKeyToSchnorr( + Buffer.from(TEST_ALICE_TAPROOT_PUBLIC_KEY_2, 'hex') + ); + const alicePayment = p2tr(alicePublicKey, undefined, regtest); + + finalizeUserInputs(transaction, alicePayment); + + expect(transaction.getInput(0).finalScriptWitness).toBeUndefined(); + expect(transaction.getInput(1).finalScriptWitness).toBeUndefined(); + }); +});