From 930fd1784cb75a6975b0ca268bbe6f78efc62b06 Mon Sep 17 00:00:00 2001 From: Polybius93 Date: Fri, 12 Jul 2024 13:15:58 +0200 Subject: [PATCH] feat: modify por calculation according to the new flow changes --- package.json | 2 +- .../proof-of-reserve-functions.ts | 27 ++++++++------- .../proof-of-reserve-handler.ts | 10 +++--- src/utilities/index.ts | 4 +++ tests/unit/proof-of-reserve.test.ts | 33 +++++-------------- tests/unit/utility.test.ts | 21 ++++++++++++ 6 files changed, 51 insertions(+), 46 deletions(-) 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..0aa1b6c 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 { isStringDefinedAndNotEmpty } from '../../utilities/index.js'; import { createTaprootMultisigPayment, deriveUnhardenedPublicKey, @@ -18,12 +19,14 @@ export async function verifyVaultDeposit( bitcoinBlockchainBlockHeight: number, bitcoinBlockchainAPI: string, bitcoinNetwork: Network -): Promise { +): Promise { try { - const fundingTransaction = await fetchBitcoinTransaction( - vault.fundingTxId, - bitcoinBlockchainAPI - ); + if (!isStringDefinedAndNotEmpty(vault.wdTxId) && !isStringDefinedAndNotEmpty(vault.fundingTxId)) + return 0; + + const txID = isStringDefinedAndNotEmpty(vault.wdTxId) ? vault.wdTxId : vault.fundingTxId; + + const fundingTransaction = await fetchBitcoinTransaction(txID, bitcoinBlockchainAPI); const isFundingTransactionConfirmed = await checkBitcoinTransactionConfirmations( fundingTransaction, @@ -31,7 +34,7 @@ export async function verifyVaultDeposit( ); if (!isFundingTransactionConfirmed) { - return false; + return 0; } const unspendableKeyCommittedToUUID = deriveUnhardenedPublicKey( @@ -52,16 +55,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/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..a2aa465 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 isStringDefinedAndNotEmpty(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..0a66af7 100644 --- a/tests/unit/utility.test.ts +++ b/tests/unit/utility.test.ts @@ -4,6 +4,7 @@ import { customShiftValue, delay, isDefined, + isStringDefinedAndNotEmpty, isUndefined, reverseBytes, shiftValue, @@ -88,6 +89,26 @@ describe('Utility Functions', () => { }); }); + describe('isStringDefinedAndNotEmpty', () => { + it('correctly identifies if a string is defined and not empty', () => { + const value = 'Hello, World!'; + const isValueDefinedAndNotEmpty = isStringDefinedAndNotEmpty(value); + expect(isValueDefinedAndNotEmpty).toBe(true); + }); + + it('correctly identifies if a string is not defined', () => { + const value = undefined; + const isValueDefinedAndNotEmpty = isStringDefinedAndNotEmpty(value); + expect(isValueDefinedAndNotEmpty).toBe(false); + }); + + it('correctly identifies if a string is defined but empty', () => { + const value = ''; + const isValueDefinedAndNotEmpty = isStringDefinedAndNotEmpty(value); + expect(isValueDefinedAndNotEmpty).toBe(false); + }); + }); + describe('compareUint8Arrays', () => { it('correctly compares two Uint8Arrays for equality', () => { const uint8ArrayA = new Uint8Array([