Page MenuHomePhabricator

[Cashtab] Add encrypted messages option (for discussion only)
AbandonedPublic

Authored by emack on Dec 4 2021, 04:49.

Details

Reviewers
bytesofman
Group Reviewers
Restricted Project
Summary

This is for discussion only - pardon the debug statements and failed test suite.

This diff builds on the standardized prefix approach in D10494 by introducing an additional encryption prefix after the protocol ID prefix. In this case, the encryption prefix flags whether this OP_RETURN message need to be decrypted or not.

The eccrypto-js library is used, which is an elliptic curve cryptography library that encrypts and decrypts messages using the same eliptic curve cryptography used by Bitcoin.

End to end encryption summary:

Sender's side

  1. Send.js flags to useBch() whether the user wants to encrypt the message or not. For now this is set to always true for development purposes to get the full end to end encryption/decryption process working first.
  2. If the encryption flag is true, useBCH.js' sendBch() function retrieves the public key corresponding to the recipient's address and then calls on eccrypto-js to encrypt the message based on that public key.
  3. The encrypted string is then added to the OP_RETURN script after all the preceding prefixes.

Recipient's side

  1. As a routine tx history update, useBCH.js' parseTx() function checks if the message is a cashtab message, and if so, will now carry out an addition check for the encryption prefix.
  2. If it's deemed to be an encrypted string, the preceding prefixes are removed, leaving the remaining encrypted string matching the string from step 3.
  3. The eccrypto-js library is then called to decrypt the encrypted message using the recipient's private key. The private key is obtained via wallet.state.slpBalancesAndUtxos.nonSlpUtxos[0].wif
  4. If the encryption is successful, the decrypted message is sent up to Tx.js for rendering. Otherwise, it is assumed the user is not authorised to view the message, which is then overwritten by a default "Encrypted Message" placeholder text for Tx.js.

Notes:

  • Currently due to bch-api constraints, the public key extracted at step 2 is based on a BCH address. I'm currently countering 'bad private key' errors from the library at step 6 so not sure if is the root cause.
  • Should the sender be able to see the unencrypted message? As it stands, the code will only allow the recipient to see the message.
Test Plan

6a040074616207656e63727970744c810493f97c0c721e7a19967510ad15bb2fae74617bcf87d5f8054fc8d8f7957d05d80d16a95d30171e1aed364629f57efd774bdebefd4780b73953dc31ce5d2ea3d156822332a8f2c993563bcf19bf784d688bb109cba40c2cc8adafd3589698ef675e4393a39d839c1610147d42dbc3a80428f0d2bb3a59f368733215ce9ef741af

  • Which is broken down into:

6a - OP_RETURN
04 - PUSHDATA
00746162 - Cashtab
07 - AppPrefixLength
656e6372797074 - Encryption flag
4c - PUSH DATA 1
81 - AppPrefixLength
Everything thereafter being the encrypted string send by the sender.
0493f97c0c721e7a19967510ad15bb2fae74617bcf87d5f8054fc8d8f7957d05d80d16a95d30171e1aed364629f57efd774bdebefd4780b73953dc31ce5d2ea3d156822332a8f2c993563bcf19bf784d688bb109cba40c2cc8adafd3589698ef675e4393a39d839c1610147d42dbc3a80428f0d2bb3a59f368733215ce9ef741af

Diff Detail

Repository
rABC Bitcoin ABC
Branch
encryptionBranch2
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 17535
Build 34896: Build Diffcashtab-tests
Build 34895: arc lint + arc unit

Event Timeline

emack requested review of this revision.Dec 4 2021, 04:50

Failed tests logs:

====== CashTab Unit Tests:  extractExternalMessage() correctly extracts an external message ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: "62696e676f656c65637472756d"
Received: "0d62696e676f656c65637472756d"
    at Object.<anonymous> (/work/web/cashtab/src/components/Common/__tests__/Ticker.test.js:190:20)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests:  Wallet without BCH balance ======
Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet without BCH balance 1`

- Snapshot  - 5
+ Received  + 5

@@ -1,8 +1,8 @@
  Array [
    <div
-     className="sc-fMiknA fHWQKC"
+     className="sc-dVhcbM fSFzLu"
    >
      <span
        aria-label="party emoji"
        role="img"
      >
@@ -24,11 +24,11 @@
       
      XEC
       to send to others
    </div>,
    <div
-     className="sc-jhAzac jLDVSr"
+     className="sc-fBuWsC ouBcJ"
    >
      0
       
      XEC
    </div>,
@@ -114,20 +114,20 @@
          cxkrr6zd
        </span>
      </div>
    </div>,
    <div
-     className="sc-TOsTZ ihWfGS"
+     className="sc-kgAjT jByKrU"
    >
      <div
-       className="sc-kgAjT kbUjME"
+       className="sc-cJSrbW fxyvyQ"
        onClick={[Function]}
      >
        XEC
      </div>
      <div
-       className="sc-kgAjT kbUjME nonactiveBtn"
+       className="sc-cJSrbW fxyvyQ nonactiveBtn"
        onClick={[Function]}
      >
        eToken
      </div>
    </div>,
    at Object.<anonymous> (/work/web/cashtab/src/components/Wallet/__tests__/Wallet.test.js:36:18)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet without BCH balance 1`

- Snapshot  - 1
+ Received  + 1

@@ -383,11 +383,11 @@
          </div>
        </form>
      </div>
    </div>,
    <div
-     className="sc-dNLxif cAbBwF"
+     className="sc-jqCOkK gIFXRY"
    >
      Signatures
    </div>,
    <div
      className="ant-collapse ant-collapse-icon-position-left sc-fjdhpX ddFLEP"
    at Object.<anonymous> (/work/web/cashtab/src/components/Send/__tests__/Send.test.js:54:18)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests:  Wallet with BCH balances ======
Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet with BCH balances 1`

- Snapshot  - 5
+ Received  + 5

@@ -1,8 +1,8 @@
  Array [
    <div
-     className="sc-fMiknA fHWQKC"
+     className="sc-dVhcbM fSFzLu"
    >
      <span
        aria-label="party emoji"
        role="img"
      >
@@ -24,11 +24,11 @@
       
      XEC
       to send to others
    </div>,
    <div
-     className="sc-jhAzac jLDVSr"
+     className="sc-fBuWsC ouBcJ"
    >
      0
       
      XEC
    </div>,
@@ -114,20 +114,20 @@
          cxkrr6zd
        </span>
      </div>
    </div>,
    <div
-     className="sc-TOsTZ ihWfGS"
+     className="sc-kgAjT jByKrU"
    >
      <div
-       className="sc-kgAjT kbUjME"
+       className="sc-cJSrbW fxyvyQ"
        onClick={[Function]}
      >
        XEC
      </div>
      <div
-       className="sc-kgAjT kbUjME nonactiveBtn"
+       className="sc-cJSrbW fxyvyQ nonactiveBtn"
        onClick={[Function]}
      >
        eToken
      </div>
    </div>,
    at Object.<anonymous> (/work/web/cashtab/src/components/Wallet/__tests__/Wallet.test.js:49:18)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet with BCH balances 1`

- Snapshot  - 1
+ Received  + 1

@@ -383,11 +383,11 @@
          </div>
        </form>
      </div>
    </div>,
    <div
-     className="sc-dNLxif cAbBwF"
+     className="sc-jqCOkK gIFXRY"
    >
      Signatures
    </div>,
    <div
      className="ant-collapse ant-collapse-icon-position-left sc-fjdhpX ddFLEP"
    at Object.<anonymous> (/work/web/cashtab/src/components/Send/__tests__/Send.test.js:68:18)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests:  Wallet with BCH balances and tokens ======
Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet with BCH balances and tokens 1`

- Snapshot  - 5
+ Received  + 5

@@ -1,8 +1,8 @@
  Array [
    <div
-     className="sc-fMiknA fHWQKC"
+     className="sc-dVhcbM fSFzLu"
    >
      <span
        aria-label="party emoji"
        role="img"
      >
@@ -24,11 +24,11 @@
       
      XEC
       to send to others
    </div>,
    <div
-     className="sc-jhAzac jLDVSr"
+     className="sc-fBuWsC ouBcJ"
    >
      0
       
      XEC
    </div>,
@@ -114,20 +114,20 @@
          cxkrr6zd
        </span>
      </div>
    </div>,
    <div
-     className="sc-TOsTZ ihWfGS"
+     className="sc-kgAjT jByKrU"
    >
      <div
-       className="sc-kgAjT kbUjME"
+       className="sc-cJSrbW fxyvyQ"
        onClick={[Function]}
      >
        XEC
      </div>
      <div
-       className="sc-kgAjT kbUjME nonactiveBtn"
+       className="sc-cJSrbW fxyvyQ nonactiveBtn"
        onClick={[Function]}
      >
        eToken
      </div>
    </div>,
    at Object.<anonymous> (/work/web/cashtab/src/components/Wallet/__tests__/Wallet.test.js:62:18)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet with BCH balances and tokens 1`

- Snapshot  - 1
+ Received  + 1

@@ -383,11 +383,11 @@
          </div>
        </form>
      </div>
    </div>,
    <div
-     className="sc-dNLxif cAbBwF"
+     className="sc-jqCOkK gIFXRY"
    >
      Signatures
    </div>,
    <div
      className="ant-collapse ant-collapse-icon-position-left sc-fjdhpX ddFLEP"
    at Object.<anonymous> (/work/web/cashtab/src/components/Send/__tests__/Send.test.js:82:18)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests:  Wallet with BCH balances and tokens and state field ======
Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet with BCH balances and tokens and state field 1`

- Snapshot  - 5
+ Received  + 5

@@ -1,15 +1,15 @@
  Array [
    <div
-     className="sc-jhAzac jLDVSr"
+     className="sc-fBuWsC ouBcJ"
    >
      0.06
       
      XEC
    </div>,
    <div
-     className="sc-fBuWsC cWYAdq"
+     className="sc-fMiknA fexmhZ"
    >
      $ 
      NaN
       
      USD
@@ -96,20 +96,20 @@
          cxkrr6zd
        </span>
      </div>
    </div>,
    <div
-     className="sc-TOsTZ ihWfGS"
+     className="sc-kgAjT jByKrU"
    >
      <div
-       className="sc-kgAjT kbUjME"
+       className="sc-cJSrbW fxyvyQ"
        onClick={[Function]}
      >
        XEC
      </div>
      <div
-       className="sc-kgAjT kbUjME nonactiveBtn"
+       className="sc-cJSrbW fxyvyQ nonactiveBtn"
        onClick={[Function]}
      >
        eToken
      </div>
    </div>,
    at Object.<anonymous> (/work/web/cashtab/src/components/Wallet/__tests__/Wallet.test.js:75:18)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet with BCH balances and tokens and state field 1`

- Snapshot  - 1
+ Received  + 1

@@ -391,11 +391,11 @@
          </div>
        </form>
      </div>
    </div>,
    <div
-     className="sc-dNLxif cAbBwF"
+     className="sc-jqCOkK gIFXRY"
    >
      Signatures
    </div>,
    <div
      className="ant-collapse ant-collapse-icon-position-left sc-fjdhpX ddFLEP"
    at Object.<anonymous> (/work/web/cashtab/src/components/Send/__tests__/Send.test.js:96:18)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests:  Without wallet defined ======
Error: expect(received).toMatchSnapshot()

Snapshot name: `Without wallet defined 1`

- Snapshot  - 1
+ Received  + 1

@@ -383,11 +383,11 @@
          </div>
        </form>
      </div>
    </div>,
    <div
-     className="sc-dNLxif cAbBwF"
+     className="sc-jqCOkK gIFXRY"
    >
      Signatures
    </div>,
    <div
      className="ant-collapse ant-collapse-icon-position-left sc-fjdhpX ddFLEP"
    at Object.<anonymous> (/work/web/cashtab/src/components/Send/__tests__/Send.test.js:114:18)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests: useBCH hook Correctly parses a "send XEC" transaction ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: [{"amountReceived": 0, "amountSent": 0.000042, "blocktime": 1614380741, "confirmations": 2721, "destinationAddress": "bitcoincash:qphpmfj0qn7znklqhrfn5dq7qh36l3vxavu346vqcl", "height": 674993, "isCashtabMessage": false, "opReturnMessage": "", "outgoingTx": true, "replyAddress": "ecash:qpmytrdsakt0axrrlswvaj069nat3p9s7cjctmjasj", "tokenTx": false, "txid": "089f2188d5771a7de0589def2b8d6c1a1f33f45b6de26d9a0ef32782f019ecf1"}]
Received: {}
    at Object.<anonymous> (/work/web/cashtab/src/hooks/__tests__/useBCH.test.js:330:61)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests: useBCH hook Correctly parses a "receive XEC" transaction ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: [{"amountReceived": 3, "amountSent": 0, "blocktime": 1612567121, "confirmations": 5637, "destinationAddress": "bitcoincash:qpmytrdsakt0axrrlswvaj069nat3p9s7ct4lsf8k9", "height": 672077, "isCashtabMessage": false, "opReturnMessage": "", "outgoingTx": false, "replyAddress": "ecash:qphpmfj0qn7znklqhrfn5dq7qh36l3vxav9up3h67g", "tokenTx": false, "txid": "42d39fbe068a40fe691f987b22fdf04b80f94d71d2fec20a58125e7b1a06d2a9"}]
Received: {}
    at Object.<anonymous> (/work/web/cashtab/src/hooks/__tests__/useBCH.test.js:337:61)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests: useBCH hook Correctly parses a "send eToken" transaction ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: [{"amountReceived": 0, "amountSent": 0.00000546, "blocktime": 1614027278, "confirmations": 3270, "destinationAddress": "bitcoincash:qzj5zu6fgg8v2we82gh76xnrk9njcregluzgaztm45", "height": 674444, "isCashtabMessage": false, "opReturnMessage": "", "outgoingTx": true, "replyAddress": "ecash:qpmytrdsakt0axrrlswvaj069nat3p9s7cjctmjasj", "tokenTx": true, "txid": "ffe3a7500dbcc98021ad581c98d9947054d1950a7f3416664715066d3d20ad72"}]
Received: {}
    at Object.<anonymous> (/work/web/cashtab/src/hooks/__tests__/useBCH.test.js:344:61)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests: useBCH hook Correctly parses a "receive eToken" transaction ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: [{"amountReceived": 0.00000546, "amountSent": 0, "blocktime": 1613859311, "confirmations": 3571, "destinationAddress": "bitcoincash:qpmytrdsakt0axrrlswvaj069nat3p9s7ct4lsf8k9", "height": 674143, "isCashtabMessage": false, "opReturnMessage": "", "outgoingTx": false, "replyAddress": "ecash:qzudj5fd9t0cknnsc3wzdd4sp46u9r42jc2d89j2kc", "tokenTx": true, "txid": "618d0dd8c0c5fa5a34c6515c865dd72bb76f8311cd6ee9aef153bab20dabc0e6"}]
Received: {}
    at Object.<anonymous> (/work/web/cashtab/src/hooks/__tests__/useBCH.test.js:351:61)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests: useBCH hook Correctly parses a "send XEC" transaction with an OP_RETURN message ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: [{"amountReceived": 0, "amountSent": 0, "blocktime": 1635507345, "confirmations": 59, "destinationAddress": undefined, "height": undefined, "isCashtabMessage": false, "opReturnMessage": {"data": [98, 105, 110, 103, 111, 101, 108, 101, 99, 116, 114, 117, 109], "type": "Buffer"}, "outgoingTx": false, "replyAddress": "ecash:qzekdmmurl75aazj6uj4vc68yrxgws0pmsgztm4atw", "tokenTx": false, "txid": "dd35690b0cefd24dcc08acba8694ecd49293f365a81372cb66c8f1c1291d97c5"}]
Received: {}
    at Object.<anonymous> (/work/web/cashtab/src/hooks/__tests__/useBCH.test.js:406:62)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
====== CashTab Unit Tests: useBCH hook Correctly parses a "receive XEC" transaction with an OP_RETURN message ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: [{"amountReceived": 0, "amountSent": 0, "blocktime": 1635511136, "confirmations": 70, "destinationAddress": undefined, "height": undefined, "isCashtabMessage": true, "opReturnMessage": {"data": [99, 97, 115, 104, 116, 97, 98, 117, 108, 97, 114], "type": "Buffer"}, "outgoingTx": false, "replyAddress": "ecash:qrxkkzsmrxcjmz8x90fx2uztt83cuu0u254w09pq5p", "tokenTx": false, "txid": "5adc33b5c0509b31c6da359177b19467c443bdc4dd37c283c0f87244c0ad63af"}]
Received: {}
    at Object.<anonymous> (/work/web/cashtab/src/hooks/__tests__/useBCH.test.js:413:62)
    at Object.asyncJestTest (/work/web/cashtab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
    at new Promise (<anonymous>)
    at mapper (/work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
    at /work/web/cashtab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
    at processTicksAndRejections (node:internal/process/task_queues:94:5)

Each failure log is accessible here:
CashTab Unit Tests: extractExternalMessage() correctly extracts an external message
CashTab Unit Tests: Wallet without BCH balance
CashTab Unit Tests: Wallet with BCH balances
CashTab Unit Tests: Wallet with BCH balances and tokens
CashTab Unit Tests: Wallet with BCH balances and tokens and state field
CashTab Unit Tests: Without wallet defined
CashTab Unit Tests: useBCH hook Correctly parses a "send XEC" transaction
CashTab Unit Tests: useBCH hook Correctly parses a "receive XEC" transaction
CashTab Unit Tests: useBCH hook Correctly parses a "send eToken" transaction
CashTab Unit Tests: useBCH hook Correctly parses a "receive eToken" transaction
CashTab Unit Tests: useBCH hook Correctly parses a "send XEC" transaction with an OP_RETURN message
CashTab Unit Tests: useBCH hook Correctly parses a "receive XEC" transaction with an OP_RETURN message