diff --git a/package.json b/package.json index b551228..5c006e5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "dlc-btc-lib", - "version": "1.0.18", + "version": "1.0.19", "description": "This library provides a comprehensive set of interfaces and functions for minting dlcBTC tokens on supported blockchains.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/functions/proof-of-reserve/proof-of-reserve-functions.ts b/src/functions/proof-of-reserve/proof-of-reserve-functions.ts index 74404bf..b155189 100644 --- a/src/functions/proof-of-reserve/proof-of-reserve-functions.ts +++ b/src/functions/proof-of-reserve/proof-of-reserve-functions.ts @@ -1,6 +1,7 @@ import { Network } from 'bitcoinjs-lib'; -import { RawVault } from 'src/models/ethereum-models.js'; +import { RawVault } from '../../models/ethereum-models.js'; +import { isNonEmptyString } from '../../utilities/index.js'; import { createTaprootMultisigPayment, deriveUnhardenedPublicKey, @@ -18,12 +19,13 @@ export async function verifyVaultDeposit( bitcoinBlockchainBlockHeight: number, bitcoinBlockchainAPI: string, bitcoinNetwork: Network -): Promise { +): Promise { try { - const fundingTransaction = await fetchBitcoinTransaction( - vault.fundingTxId, - bitcoinBlockchainAPI - ); + if (!isNonEmptyString(vault.wdTxId) && !isNonEmptyString(vault.fundingTxId)) return 0; + + const txID = isNonEmptyString(vault.wdTxId) ? vault.wdTxId : vault.fundingTxId; + + const fundingTransaction = await fetchBitcoinTransaction(txID, bitcoinBlockchainAPI); const isFundingTransactionConfirmed = await checkBitcoinTransactionConfirmations( fundingTransaction, @@ -31,7 +33,7 @@ export async function verifyVaultDeposit( ); if (!isFundingTransactionConfirmed) { - return false; + return 0; } const unspendableKeyCommittedToUUID = deriveUnhardenedPublicKey( @@ -52,16 +54,12 @@ export async function verifyVaultDeposit( ); if (!vaultTransactionOutput) { - return false; - } - - if (vaultTransactionOutput.value !== vault.valueLocked.toNumber()) { - return false; + return 0; } - return true; + return vaultTransactionOutput.value; } catch (error) { console.log(`Error verifying Vault Deposit: ${error}`); - return false; + return 0; } } diff --git a/src/models/ethereum-models.ts b/src/models/ethereum-models.ts index e40f2db..6ebc35c 100644 --- a/src/models/ethereum-models.ts +++ b/src/models/ethereum-models.ts @@ -18,7 +18,6 @@ export enum VaultState { CLOSING = 2, CLOSED = 3, PENDING = 4, - FUNDING = 5, } export interface RawVault { diff --git a/src/proof-of-reserve-handlers/proof-of-reserve-handler.ts b/src/proof-of-reserve-handlers/proof-of-reserve-handler.ts index 98b8e8c..9639637 100644 --- a/src/proof-of-reserve-handlers/proof-of-reserve-handler.ts +++ b/src/proof-of-reserve-handlers/proof-of-reserve-handler.ts @@ -31,17 +31,15 @@ export class ProofOfReserveHandler { ); const verifiedDeposits = await Promise.all( - vaults.map(async vault => { - return (await verifyVaultDeposit( + vaults.map(vault => + verifyVaultDeposit( vault, derivedAttestorGroupPublicKey, bitcoinBlockchainBlockHeight, this.bitcoinBlockchainAPI, this.bitcoinNetwork - )) === true - ? vault.valueLocked.toNumber() - : 0; - }) + ) + ) ); return verifiedDeposits.reduce((a, b) => a + b, 0); } diff --git a/src/utilities/index.ts b/src/utilities/index.ts index b691e07..babfb8f 100644 --- a/src/utilities/index.ts +++ b/src/utilities/index.ts @@ -45,6 +45,10 @@ export function isDefined(argument: T | undefined): argument is T { return !isUndefined(argument); } +export function isNonEmptyString(string: string | undefined): boolean { + return isDefined(string) && string !== ''; +} + export function compareUint8Arrays(a: Uint8Array, b: Uint8Array): boolean { return a.length === b.length && a.every((value, index) => value === b[index]); } diff --git a/tests/unit/proof-of-reserve.test.ts b/tests/unit/proof-of-reserve.test.ts index e2d22c1..f682b77 100644 --- a/tests/unit/proof-of-reserve.test.ts +++ b/tests/unit/proof-of-reserve.test.ts @@ -7,7 +7,6 @@ import { TEST_TESTNET_ATTESTOR_UNHARDENED_DERIVED_PUBLIC_KEY_1 } from '../mocks/ import { TEST_TESTNET_FUNDING_TRANSACTION_1, TEST_TESTNET_FUNDING_TRANSACTION_2, - TEST_TESTNET_FUNDING_TRANSACTION_3, } from '../mocks/bitcoin-transaction.test.constants.js'; import { TEST_BITCOIN_BLOCKCHAIN_BLOCK_HEIGHT_1, @@ -20,7 +19,7 @@ describe('Proof of Reserve Calculation', () => { jest.clearAllMocks(); }); describe('verifyVaultDeposit', () => { - it("should return true when the vault's funding transaction is confirmed, contains an output with the multisig's script, and the output's value matches the vault's valueLocked field", async () => { + it("should return the expected value when the vault's funding transaction is confirmed, contains an output with the multisig's script, and the output's value matches the vault's valueLocked field", async () => { jest .spyOn(bitcoinRequestFunctions, 'fetchBitcoinTransaction') .mockImplementationOnce(async () => TEST_TESTNET_FUNDING_TRANSACTION_1); @@ -33,10 +32,10 @@ describe('Proof of Reserve Calculation', () => { testnet ); - expect(result).toBe(true); + expect(result).toBe(10000000); }); - it('should return false if the funding transaction is not found', async () => { + it('should return 0 if the funding transaction is not found', async () => { jest .spyOn(bitcoinRequestFunctions, 'fetchBitcoinTransaction') .mockImplementationOnce(async () => { @@ -51,10 +50,10 @@ describe('Proof of Reserve Calculation', () => { testnet ); - expect(result).toBe(false); + expect(result).toBe(0); }); - it("should return false when the vault's funding transaction is not yet confirmed", async () => { + it("should return 0 when the vault's funding transaction is not yet confirmed", async () => { jest .spyOn(bitcoinRequestFunctions, 'fetchBitcoinTransaction') .mockImplementationOnce(async () => TEST_TESTNET_FUNDING_TRANSACTION_1); @@ -67,10 +66,10 @@ describe('Proof of Reserve Calculation', () => { testnet ); - expect(result).toBe(false); + expect(result).toBe(0); }); - it("should return false if the vault's funding transaction lacks an output with the multisig's script", async () => { + it("should return 0 if the vault's funding transaction lacks an output with the multisig's script", async () => { jest .spyOn(bitcoinRequestFunctions, 'fetchBitcoinTransaction') .mockImplementationOnce(async () => TEST_TESTNET_FUNDING_TRANSACTION_2); @@ -83,23 +82,7 @@ describe('Proof of Reserve Calculation', () => { testnet ); - expect(result).toBe(false); - }); - - it("should return false if the output value related to the multisig script differs from the vault's valueLocked field in the funding transaction", async () => { - jest - .spyOn(bitcoinRequestFunctions, 'fetchBitcoinTransaction') - .mockImplementationOnce(async () => TEST_TESTNET_FUNDING_TRANSACTION_3); - - const result = await verifyVaultDeposit( - TEST_VAULT_2, - Buffer.from(TEST_TESTNET_ATTESTOR_UNHARDENED_DERIVED_PUBLIC_KEY_1, 'hex'), - TEST_BITCOIN_BLOCKCHAIN_BLOCK_HEIGHT_1, - TEST_TESTNET_BITCOIN_BLOCKCHAIN_API, - testnet - ); - - expect(result).toBe(false); + expect(result).toBe(0); }); }); }); diff --git a/tests/unit/utility.test.ts b/tests/unit/utility.test.ts index 546246a..9677c9b 100644 --- a/tests/unit/utility.test.ts +++ b/tests/unit/utility.test.ts @@ -4,6 +4,7 @@ import { customShiftValue, delay, isDefined, + isNonEmptyString, isUndefined, reverseBytes, shiftValue, @@ -88,6 +89,26 @@ describe('Utility Functions', () => { }); }); + describe('isNonEmptyString', () => { + it('correctly identifies if a string is defined and not empty', () => { + const value = 'Hello, World!'; + const isValueDefinedAndNotEmpty = isNonEmptyString(value); + expect(isValueDefinedAndNotEmpty).toBe(true); + }); + + it('correctly identifies if a string is not defined', () => { + const value = undefined; + const isValueDefinedAndNotEmpty = isNonEmptyString(value); + expect(isValueDefinedAndNotEmpty).toBe(false); + }); + + it('correctly identifies if a string is defined but empty', () => { + const value = ''; + const isValueDefinedAndNotEmpty = isNonEmptyString(value); + expect(isValueDefinedAndNotEmpty).toBe(false); + }); + }); + describe('compareUint8Arrays', () => { it('correctly compares two Uint8Arrays for equality', () => { const uint8ArrayA = new Uint8Array([