Page MenuHomePhabricator

[Cashtab] Use updated ecash-coinselect lib to create min fee txs
AbandonedPublic

Authored by bytesofman on Sep 20 2023, 05:11.

Details

Reviewers
Fabien
Group Reviewers
Restricted Project
Summary

T3294

We explored creating our own ecash-coinselect library, but quickly ran into complications. Upon review, I think that library was trying to do too much. In particular, the handling of chronik utxos should be left more to the app developer.

This diff

  1. Refactors ecash-coinselect based on coinselect from BitcoinJS (some mods: throws errors, uses eCash dust threshhold), updating JS syntax
  2. Implements this library in Cashtab
  3. Commence refactor of Cashtab transaction functions by initializing new directory, unit tests, and function for sending XEC transactions, using ecash-coinselect
  4. Implement this new function on the Send.js screen of Cashtab to send simple eCash transactions with a fee of 1 sat/byte

It's useful to keep this in one diff as we can show that the upgrade to ecash-coinselect is practically useful (automated unit tests exist in both parts of the monorepo).

Using a single transaction.fixtures.js file to hold fixtures dramatically simplifies the current approach (importing mocks from dozens of files). Because Cashtab creates many types of transactions and the existing functions are unit tested and work, this implementation should be phased in. Legacy functions may be deprecated as they are obsoleted by improved and refactored functions.

Test Plan
cd cashtab/
npm test

npm start
Send a normal xec tx with no op_return msg
Observe it broadcasts 1 sat/byte
Send an OP_RETURN tx
Observe it broadcasts with higher fee

cd modules/ecash-coinselect
npm test

Diff Detail

Repository
rABC Bitcoin ABC
Branch
cashtab-coinselect
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 25102
Build 49792: Build Diffcashtab-tests
Build 49791: arc lint + arc unit

Event Timeline

bytesofman updated this revision to Diff 42283.

remove debug logging

Needs self-review and context for the longer term plan around this approach

cashtab/src/transactions/__tests__/transactions.test.js
78 โ†—(On Diff #42283)

todo: put this in fixtures

cashtab/src/transactions/transactions.fixtures.js
6 โ†—(On Diff #42283)

๐Ÿ‘€

28 โ†—(On Diff #42283)

These need to be in the fixtures as they are used for transaction signing in tested functions. intentional.

cashtab/src/transactions/transactions.js
61 โ†—(On Diff #42283)

remove debug logging

Add simplified signing function, add new test vectore, remove debug logging

bytesofman edited the summary of this revision. (Show Details)

add test vector for sending to p2sh

add p2sh destination address test vector

Move generated items out of fixtures file

Move generated mocks to a marked file

Better code comments and variable names

need some test cases for tx signing errors

cashtab/src/components/Send/Send.js
443 โ†—(On Diff #42301)

For now, only use this function if you are not sending a one-to-many tx and you are not sending an OP_RETURN msg.

cashtab/src/transactions/fixtures/index.js
10 โ†—(On Diff #42301)

These test vectors are manually constructed by

  1. Creating the wallet in ./mocks, sending utxos to it
  2. Based on that utxo set and balance, manually create tests for different feeRate, satsToSend, and destinationAddress
  3. Run sendXecToOneAddress to get the hex. Load it into Electrum and inspect for txid and expected fee rate.

So, not really @generated, although for review purposes, just need to verify that description matches what is going on with the wallet, feeRate, satsToSend, and destinationAddress parameters.

cashtab/src/transactions/transactions.js
19 โ†—(On Diff #42301)

coinselect expects utxos formatted as [...{txid, vout, value}]

chronik-client returns utxos with txid and vout inside the outpoint key, and with vout labeled outIdx. Would be nice to make this change to chronik. I have not looked into the complications for this.

This helper function is trivial to implement and deprecate if it turns out this chronik change is not a big deal. So, doing it this way for now.

35 โ†—(On Diff #42301)

Note that this function has unit test coverage as it is called by sendXecToOneAddress -- won't get the raw hex values if signing fails.

Add error case unit test for signInputs

cashtab/src/transactions/transactions.js
24 โ†—(On Diff #42302)

note that coinselect can take addresses in cashaddr format. It does not consider the address and just leaves it untouched as part of the object.

The library uses baseline size estimates and does not change estimates for input or output types (except for considering script)

https://github.com/bitcoinjs/coinselect/blob/5d040215074fe3aa270a8c5eb1145d86c2fc719b/utils.js#L1C1-L1C1

Perhaps there is room for more optimization, but these values seem to work well enough for the cases considered in these unit tests.

Our attempt to exactlySpecify transaction size in ecash-coinselect ended up being low ROI -- so unless and until we find some compelling reason to modify the coinselect approach --- imo should be treated as good. At any rate, it is much better than Cashtab's current approach.

Fabien requested changes to this revision.Sep 21 2023, 08:09
Fabien added a subscriber: Fabien.

I looked closely at the coinselect library, and I'm not sold to this solution:

  • It obviously expects some format that is close but not similar to chronik utxos, adding some boilerplate to convert between the formats
  • It doesn't support txs with more than 253 in/outs
  • It doesn't manage the dust in an eCash compatible way
  • As a consequence you can end up with a change output which is below the dust threshold, which is not handled by your code and would cause your tx to get rejected

These drawbacks are to put in perspective with the gain: you don't have to write your own library, saving code.
How much code ? Well, I ran the numbers. ALL the code you are currently using, with the 2 selection algos behind the scene, the entire utils.js file, the segwit support we don't need etc., including all newlines and comment: the total is 168 lines.

Your function to send XEC, only in the special case of of a single output, is 158 lines.

My conclusion is that it's not worth it. A simple utxo selection library (like coinselect) is NOT a difficult task to complete. You even have the option to reuse some of the code from coinselect as it's MIT.
So let's not go down the leftpad rabbit hole and rather offer a seamless integration to devs on eCash.

cashtab/src/components/Send/Send.js
447 โ†—(On Diff #42302)
This revision now requires changes to proceed.Sep 21 2023, 08:09

To create and implement an ecash-specific coinselect lib

Refactor and implement ecash-coinselect

bytesofman edited the test plan for this revision. (Show Details)
bytesofman retitled this revision from [Cashtab] Use coinselect to create min fee txs to [Cashtab] Use updated ecash-coinselect lib to create min fee txs.

Fix local install dependency in package-lock.json from local testing, remove p2sh comments

Failed tests logs:

====== CashTab Unit Tests:  Verify handleUpdateWallet() correctly initializes the active wallet ======
assert.strictEqual(received, expected)

Expected value to strictly be equal to:
  true
Received:
  false
    at Object.<anonymous> (/work/cashtab/src/hooks/__tests__/useWallet.test.js:56:12)
    at runNextTicks (node:internal/process/task_queues:61:5)
    at processImmediate (node:internal/timers:437:9)
====== CashTab Unit Tests:  Verify processChronikWsMsg() processes AddedToMempool events ======
assert.notEqual(received, expected)

Expected value to not be equal to:
  false
Received:
  false
    at Object.<anonymous> (/work/cashtab/src/hooks/__tests__/useWallet.test.js:68:12)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
====== CashTab Unit Tests:  Without wallet defined ======
Error: expect(received).toMatchSnapshot()

Snapshot name: `Without wallet defined 1`

- Snapshot  - 1
+ Received  + 2

@@ -61,17 +61,18 @@
      >
        <svg
          aria-hidden="true"
          data-icon="import"
          fill="currentColor"
+         fillRule="evenodd"
          focusable="false"
          height="1em"
          viewBox="64 64 896 896"
          width="1em"
        >
          <path
-           d="M888.3 757.4h-53.8c-4.2 0-7.7 3.5-7.7 7.7v61.8H197.1V197.1h629.8v61.8c0 4.2 3.5 7.7 7.7 7.7h53.8c4.2 0 7.7-3.4 7.7-7.7V158.7c0-17-13.7-30.7-30.7-30.7H158.7c-17 0-30.7 13.7-30.7 30.7v706.6c0 17 13.7 30.7 30.7 30.7h706.6c17 0 30.7-13.7 30.7-30.7V765.1c0-4.3-3.5-7.7-7.7-7.7zM902 476H588v-76c0-6.7-7.8-10.5-13-6.3l-141.9 112a8 8 0 000 12.6l141.9 112c5.3 4.2 13 .4 13-6.3v-76h314c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z"
+           d="M880 912H144c-17.7 0-32-14.3-32-32V144c0-17.7 14.3-32 32-32h360c4.4 0 8 3.6 8 8v56c0 4.4-3.6 8-8 8H184v656h656V520c0-4.4 3.6-8 8-8h56c4.4 0 8 3.6 8 8v360c0 17.7-14.3 32-32 32zM653.3 424.6l52.2 52.2a8.01 8.01 0 01-4.7 13.6l-179.4 21c-5.1.6-9.5-3.7-8.9-8.9l21-179.4c.8-6.6 8.9-9.4 13.6-4.7l52.4 52.4 256.2-256.2c3.1-3.1 8.2-3.1 11.3 0l42.4 42.4c3.1 3.1 3.1 8.2 0 11.3L653.3 424.6z"
          />
        </svg>
      </span>
       Import Wallet
    </button>
    at Object.<anonymous> (/work/cashtab/src/components/Receive/__tests__/Receive.test.js:107:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)Error: expect(received).toMatchSnapshot()

Snapshot name: `Without wallet defined 1`

- Snapshot  - 6
+ Received  + 0

@@ -179,22 +179,16 @@
                            <label
                              className="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item sc-fBuWsC bHZMFZ"
                            >
                              <span
                                className="ant-checkbox"
-                               style={Object {}}
                              >
                                <input
                                  checked={false}
                                  className="ant-checkbox-input"
                                  disabled={false}
-                                 onBlur={[Function]}
                                  onChange={[Function]}
-                                 onFocus={[Function]}
-                                 onKeyDown={[Function]}
-                                 onKeyPress={[Function]}
-                                 onKeyUp={[Function]}
                                  type="checkbox"
                                />
                                <span
                                  className="ant-checkbox-inner"
                                />
    at Object.<anonymous> (/work/cashtab/src/components/Alias/__tests__/Alias.test.js:110:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)Error: expect(received).toMatchSnapshot()

Snapshot name: `Without wallet defined 1`

- Snapshot  - 0
+ Received  + 2

@@ -446,13 +446,15 @@
                            <textarea
                              autoComplete="off"
                              className="ant-input"
                              disabled={false}
                              name="address"
+                             onBlur={[Function]}
                              onChange={[Function]}
                              onCompositionEnd={[Function]}
                              onCompositionStart={[Function]}
+                             onFocus={[Function]}
                              onKeyDown={[Function]}
                              placeholder="One address & value per line, separated by comma 
  e.g. 
  ecash:qpatql05s9jfavnu0tv6lkjjk25n6tmj9gkpyrlwu8,500 
  ecash:qzvydd4n3lm3xv62cx078nu9rg0e3srmqq0knykfed,700"
    at Object.<anonymous> (/work/cashtab/src/components/Send/__tests__/Send.test.js:107:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)Error: expect(received).toMatchSnapshot()

Snapshot name: `Without wallet defined 1`

- Snapshot  - 1
+ Received  + 2

@@ -61,17 +61,18 @@
      >
        <svg
          aria-hidden="true"
          data-icon="import"
          fill="currentColor"
+         fillRule="evenodd"
          focusable="false"
          height="1em"
          viewBox="64 64 896 896"
          width="1em"
        >
          <path
-           d="M888.3 757.4h-53.8c-4.2 0-7.7 3.5-7.7 7.7v61.8H197.1V197.1h629.8v61.8c0 4.2 3.5 7.7 7.7 7.7h53.8c4.2 0 7.7-3.4 7.7-7.7V158.7c0-17-13.7-30.7-30.7-30.7H158.7c-17 0-30.7 13.7-30.7 30.7v706.6c0 17 13.7 30.7 30.7 30.7h706.6c17 0 30.7-13.7 30.7-30.7V765.1c0-4.3-3.5-7.7-7.7-7.7zM902 476H588v-76c0-6.7-7.8-10.5-13-6.3l-141.9 112a8 8 0 000 12.6l141.9 112c5.3 4.2 13 .4 13-6.3v-76h314c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z"
+           d="M880 912H144c-17.7 0-32-14.3-32-32V144c0-17.7 14.3-32 32-32h360c4.4 0 8 3.6 8 8v56c0 4.4-3.6 8-8 8H184v656h656V520c0-4.4 3.6-8 8-8h56c4.4 0 8 3.6 8 8v360c0 17.7-14.3 32-32 32zM653.3 424.6l52.2 52.2a8.01 8.01 0 01-4.7 13.6l-179.4 21c-5.1.6-9.5-3.7-8.9-8.9l21-179.4c.8-6.6 8.9-9.4 13.6-4.7l52.4 52.4 256.2-256.2c3.1-3.1 8.2-3.1 11.3 0l42.4 42.4c3.1 3.1 3.1 8.2 0 11.3L653.3 424.6z"
          />
        </svg>
      </span>
       Import Wallet
    </button>
    at Object.<anonymous> (/work/cashtab/src/components/Home/__tests__/Home.test.js:88:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)Error: expect(received).toMatchSnapshot()

Snapshot name: `Without wallet defined 1`

- Snapshot  - 3
+ Received  + 6

@@ -132,17 +132,18 @@
        >
          <svg
            aria-hidden="true"
            data-icon="import"
            fill="currentColor"
+           fillRule="evenodd"
            focusable="false"
            height="1em"
            viewBox="64 64 896 896"
            width="1em"
          >
            <path
-             d="M888.3 757.4h-53.8c-4.2 0-7.7 3.5-7.7 7.7v61.8H197.1V197.1h629.8v61.8c0 4.2 3.5 7.7 7.7 7.7h53.8c4.2 0 7.7-3.4 7.7-7.7V158.7c0-17-13.7-30.7-30.7-30.7H158.7c-17 0-30.7 13.7-30.7 30.7v706.6c0 17 13.7 30.7 30.7 30.7h706.6c17 0 30.7-13.7 30.7-30.7V765.1c0-4.3-3.5-7.7-7.7-7.7zM902 476H588v-76c0-6.7-7.8-10.5-13-6.3l-141.9 112a8 8 0 000 12.6l141.9 112c5.3 4.2 13 .4 13-6.3v-76h314c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z"
+             d="M880 912H144c-17.7 0-32-14.3-32-32V144c0-17.7 14.3-32 32-32h360c4.4 0 8 3.6 8 8v56c0 4.4-3.6 8-8 8H184v656h656V520c0-4.4 3.6-8 8-8h56c4.4 0 8 3.6 8 8v360c0 17.7-14.3 32-32 32zM653.3 424.6l52.2 52.2a8.01 8.01 0 01-4.7 13.6l-179.4 21c-5.1.6-9.5-3.7-8.9-8.9l21-179.4c.8-6.6 8.9-9.4 13.6-4.7l52.4 52.4 256.2-256.2c3.1-3.1 8.2-3.1 11.3 0l42.4 42.4c3.1 3.1 3.1 8.2 0 11.3L653.3 424.6z"
            />
          </svg>
        </span>
         Import Wallet
      </button>
@@ -402,17 +403,18 @@
            >
              <svg
                aria-hidden="true"
                data-icon="close"
                fill="currentColor"
+               fillRule="evenodd"
                focusable="false"
                height="1em"
                viewBox="64 64 896 896"
                width="1em"
              >
                <path
-                 d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
+                 d="M799.86 166.31c.02 0 .04.02.08.06l57.69 57.7c.04.03.05.05.06.08a.12.12 0 010 .06c0 .03-.02.05-.06.09L569.93 512l287.7 287.7c.04.04.05.06.06.09a.12.12 0 010 .07c0 .02-.02.04-.06.08l-57.7 57.69c-.03.04-.05.05-.07.06a.12.12 0 01-.07 0c-.03 0-.05-.02-.09-.06L512 569.93l-287.7 287.7c-.04.04-.06.05-.09.06a.12.12 0 01-.07 0c-.02 0-.04-.02-.08-.06l-57.69-57.7c-.04-.03-.05-.05-.06-.07a.12.12 0 010-.07c0-.03.02-.05.06-.09L454.07 512l-287.7-287.7c-.04-.04-.05-.06-.06-.09a.12.12 0 010-.07c0-.02.02-.04.06-.08l57.7-57.69c.03-.04.05-.05.07-.06a.12.12 0 01.07 0c.03 0 .05.02.09.06L512 454.07l287.7-287.7c.04-.04.06-.05.09-.06a.12.12 0 01.07 0z"
                />
              </svg>
            </span>
          </span>
        </button>
@@ -465,17 +467,18 @@
            >
              <svg
                aria-hidden="true"
                data-icon="close"
                fill="currentColor"
+               fillRule="evenodd"
                focusable="false"
                height="1em"
                viewBox="64 64 896 896"
                width="1em"
              >
                <path
-                 d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
+                 d="M799.86 166.31c.02 0 .04.02.08.06l57.69 57.7c.04.03.05.05.06.08a.12.12 0 010 .06c0 .03-.02.05-.06.09L569.93 512l287.7 287.7c.04.04.05.06.06.09a.12.12 0 010 .07c0 .02-.02.04-.06.08l-57.7 57.69c-.03.04-.05.05-.07.06a.12.12 0 01-.07 0c-.03 0-.05-.02-.09-.06L512 569.93l-287.7 287.7c-.04.04-.06.05-.09.06a.12.12 0 01-.07 0c-.02 0-.04-.02-.08-.06l-57.69-57.7c-.04-.03-.05-.05-.06-.07a.12.12 0 010-.07c0-.03.02-.05.06-.09L454.07 512l-287.7-287.7c-.04-.04-.05-.06-.06-.09a.12.12 0 010-.07c0-.02.02-.04.06-.08l57.7-57.69c.03-.04.05-.05.07-.06a.12.12 0 01.07 0c.03 0 .05.02.09.06L512 454.07l287.7-287.7c.04-.04.06-.05.09-.06a.12.12 0 01.07 0z"
                />
              </svg>
            </span>
          </span>
        </button>
    at Object.<anonymous> (/work/cashtab/src/components/Configure/__tests__/Configure.test.js:58:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)
====== CashTab Unit Tests:  Wallet without XEC balance ======
Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet without XEC balance 1`

- Snapshot  - 6
+ Received  + 0

@@ -184,22 +184,16 @@
                            <label
                              className="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-in-form-item sc-fBuWsC bHZMFZ"
                            >
                              <span
                                className="ant-checkbox ant-checkbox-checked"
-                               style={Object {}}
                              >
                                <input
                                  checked={true}
                                  className="ant-checkbox-input"
                                  disabled={false}
-                                 onBlur={[Function]}
                                  onChange={[Function]}
-                                 onFocus={[Function]}
-                                 onKeyDown={[Function]}
-                                 onKeyPress={[Function]}
-                                 onKeyUp={[Function]}
                                  type="checkbox"
                                />
                                <span
                                  className="ant-checkbox-inner"
                                />
    at Object.<anonymous> (/work/cashtab/src/components/Alias/__tests__/Alias.test.js:44:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)
====== CashTab Unit Tests:  Wallet with XEC balances ======
Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet with XEC balances 1`

- Snapshot  - 6
+ Received  + 0

@@ -184,22 +184,16 @@
                            <label
                              className="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-in-form-item sc-fBuWsC bHZMFZ"
                            >
                              <span
                                className="ant-checkbox ant-checkbox-checked"
-                               style={Object {}}
                              >
                                <input
                                  checked={true}
                                  className="ant-checkbox-input"
                                  disabled={false}
-                                 onBlur={[Function]}
                                  onChange={[Function]}
-                                 onFocus={[Function]}
-                                 onKeyDown={[Function]}
-                                 onKeyPress={[Function]}
-                                 onKeyUp={[Function]}
                                  type="checkbox"
                                />
                                <span
                                  className="ant-checkbox-inner"
                                />
    at Object.<anonymous> (/work/cashtab/src/components/Alias/__tests__/Alias.test.js:58:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)
====== CashTab Unit Tests:  Wallet with XEC balances and tokens ======
Error: expect(received).toMatchSnapshot()

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

- Snapshot  - 6
+ Received  + 0

@@ -184,22 +184,16 @@
                            <label
                              className="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-in-form-item sc-fBuWsC bHZMFZ"
                            >
                              <span
                                className="ant-checkbox ant-checkbox-checked"
-                               style={Object {}}
                              >
                                <input
                                  checked={true}
                                  className="ant-checkbox-input"
                                  disabled={false}
-                                 onBlur={[Function]}
                                  onChange={[Function]}
-                                 onFocus={[Function]}
-                                 onKeyDown={[Function]}
-                                 onKeyPress={[Function]}
-                                 onKeyUp={[Function]}
                                  type="checkbox"
                                />
                                <span
                                  className="ant-checkbox-inner"
                                />
    at Object.<anonymous> (/work/cashtab/src/components/Alias/__tests__/Alias.test.js:72:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)
====== CashTab Unit Tests:  Wallet with XEC balances and tokens and state field ======
Error: expect(received).toMatchSnapshot()

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

- Snapshot  - 6
+ Received  + 0

@@ -189,22 +189,16 @@
                            <label
                              className="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-in-form-item sc-fBuWsC bHZMFZ"
                            >
                              <span
                                className="ant-checkbox ant-checkbox-checked"
-                               style={Object {}}
                              >
                                <input
                                  checked={true}
                                  className="ant-checkbox-input"
                                  disabled={false}
-                                 onBlur={[Function]}
                                  onChange={[Function]}
-                                 onFocus={[Function]}
-                                 onKeyDown={[Function]}
-                                 onKeyPress={[Function]}
-                                 onKeyUp={[Function]}
                                  type="checkbox"
                                />
                                <span
                                  className="ant-checkbox-inner"
                                />
    at Object.<anonymous> (/work/cashtab/src/components/Alias/__tests__/Alias.test.js:88:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)
====== 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  - 0
+ Received  + 1

@@ -317,10 +317,11 @@
                            role="button"
                            tabIndex="0"
                          >
                            <input
                              accept=""
+                             disabled={false}
                              multiple={false}
                              onChange={[Function]}
                              onClick={[Function]}
                              style={
                                Object {
    at Object.<anonymous> (/work/cashtab/src/components/Tokens/__tests__/Tokens.test.js:88:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)Error: expect(received).toMatchSnapshot()

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

- Snapshot  - 0
+ Received  + 2

@@ -456,13 +456,15 @@
                            <textarea
                              autoComplete="off"
                              className="ant-input"
                              disabled={false}
                              name="address"
+                             onBlur={[Function]}
                              onChange={[Function]}
                              onCompositionEnd={[Function]}
                              onCompositionStart={[Function]}
+                             onFocus={[Function]}
                              onKeyDown={[Function]}
                              placeholder="One address & value per line, separated by comma 
  e.g. 
  ecash:qpatql05s9jfavnu0tv6lkjjk25n6tmj9gkpyrlwu8,500 
  ecash:qzvydd4n3lm3xv62cx078nu9rg0e3srmqq0knykfed,700"
    at Object.<anonymous> (/work/cashtab/src/components/Send/__tests__/Send.test.js:88:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)Error: expect(received).toMatchSnapshot()

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

- Snapshot  - 0
+ Received  + 1

@@ -251,10 +251,11 @@
                        role="button"
                        tabIndex="0"
                      >
                        <input
                          accept=""
+                         disabled={false}
                          multiple={false}
                          onChange={[Function]}
                          onClick={[Function]}
                          style={
                            Object {
    at Object.<anonymous> (/work/cashtab/src/components/Tokens/__tests__/CreateTokenForm.test.js:46:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)
====== CashTab Unit Tests:  Wallet without BCH balance ======
Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet without BCH balance 1`

- Snapshot  - 0
+ Received  + 2

@@ -451,13 +451,15 @@
                            <textarea
                              autoComplete="off"
                              className="ant-input"
                              disabled={false}
                              name="address"
+                             onBlur={[Function]}
                              onChange={[Function]}
                              onCompositionEnd={[Function]}
                              onCompositionStart={[Function]}
+                             onFocus={[Function]}
                              onKeyDown={[Function]}
                              placeholder="One address & value per line, separated by comma 
  e.g. 
  ecash:qpatql05s9jfavnu0tv6lkjjk25n6tmj9gkpyrlwu8,500 
  ecash:qzvydd4n3lm3xv62cx078nu9rg0e3srmqq0knykfed,700"
    at Object.<anonymous> (/work/cashtab/src/components/Send/__tests__/Send.test.js:44:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)
====== CashTab Unit Tests:  Wallet with BCH balances ======
Error: expect(received).toMatchSnapshot()

Snapshot name: `Wallet with BCH balances 1`

- Snapshot  - 0
+ Received  + 2

@@ -451,13 +451,15 @@
                            <textarea
                              autoComplete="off"
                              className="ant-input"
                              disabled={false}
                              name="address"
+                             onBlur={[Function]}
                              onChange={[Function]}
                              onCompositionEnd={[Function]}
                              onCompositionStart={[Function]}
+                             onFocus={[Function]}
                              onKeyDown={[Function]}
                              placeholder="One address & value per line, separated by comma 
  e.g. 
  ecash:qpatql05s9jfavnu0tv6lkjjk25n6tmj9gkpyrlwu8,500 
  ecash:qzvydd4n3lm3xv62cx078nu9rg0e3srmqq0knykfed,700"
    at Object.<anonymous> (/work/cashtab/src/components/Send/__tests__/Send.test.js:58:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)
====== CashTab Unit Tests:  Wallet with BCH balances and tokens ======
Error: expect(received).toMatchSnapshot()

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

- Snapshot  - 0
+ Received  + 2

@@ -451,13 +451,15 @@
                            <textarea
                              autoComplete="off"
                              className="ant-input"
                              disabled={false}
                              name="address"
+                             onBlur={[Function]}
                              onChange={[Function]}
                              onCompositionEnd={[Function]}
                              onCompositionStart={[Function]}
+                             onFocus={[Function]}
                              onKeyDown={[Function]}
                              placeholder="One address & value per line, separated by comma 
  e.g. 
  ecash:qpatql05s9jfavnu0tv6lkjjk25n6tmj9gkpyrlwu8,500 
  ecash:qzvydd4n3lm3xv62cx078nu9rg0e3srmqq0knykfed,700"
    at Object.<anonymous> (/work/cashtab/src/components/Send/__tests__/Send.test.js:72:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)Error: expect(received).toMatchSnapshot()

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

- Snapshot  - 3
+ Received  + 6

@@ -132,17 +132,18 @@
        >
          <svg
            aria-hidden="true"
            data-icon="import"
            fill="currentColor"
+           fillRule="evenodd"
            focusable="false"
            height="1em"
            viewBox="64 64 896 896"
            width="1em"
          >
            <path
-             d="M888.3 757.4h-53.8c-4.2 0-7.7 3.5-7.7 7.7v61.8H197.1V197.1h629.8v61.8c0 4.2 3.5 7.7 7.7 7.7h53.8c4.2 0 7.7-3.4 7.7-7.7V158.7c0-17-13.7-30.7-30.7-30.7H158.7c-17 0-30.7 13.7-30.7 30.7v706.6c0 17 13.7 30.7 30.7 30.7h706.6c17 0 30.7-13.7 30.7-30.7V765.1c0-4.3-3.5-7.7-7.7-7.7zM902 476H588v-76c0-6.7-7.8-10.5-13-6.3l-141.9 112a8 8 0 000 12.6l141.9 112c5.3 4.2 13 .4 13-6.3v-76h314c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z"
+             d="M880 912H144c-17.7 0-32-14.3-32-32V144c0-17.7 14.3-32 32-32h360c4.4 0 8 3.6 8 8v56c0 4.4-3.6 8-8 8H184v656h656V520c0-4.4 3.6-8 8-8h56c4.4 0 8 3.6 8 8v360c0 17.7-14.3 32-32 32zM653.3 424.6l52.2 52.2a8.01 8.01 0 01-4.7 13.6l-179.4 21c-5.1.6-9.5-3.7-8.9-8.9l21-179.4c.8-6.6 8.9-9.4 13.6-4.7l52.4 52.4 256.2-256.2c3.1-3.1 8.2-3.1 11.3 0l42.4 42.4c3.1 3.1 3.1 8.2 0 11.3L653.3 424.6z"
            />
          </svg>
        </span>
         Import Wallet
      </button>
@@ -402,17 +403,18 @@
            >
              <svg
                aria-hidden="true"
                data-icon="close"
                fill="currentColor"
+               fillRule="evenodd"
                focusable="false"
                height="1em"
                viewBox="64 64 896 896"
                width="1em"
              >
                <path
-                 d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
+                 d="M799.86 166.31c.02 0 .04.02.08.06l57.69 57.7c.04.03.05.05.06.08a.12.12 0 010 .06c0 .03-.02.05-.06.09L569.93 512l287.7 287.7c.04.04.05.06.06.09a.12.12 0 010 .07c0 .02-.02.04-.06.08l-57.7 57.69c-.03.04-.05.05-.07.06a.12.12 0 01-.07 0c-.03 0-.05-.02-.09-.06L512 569.93l-287.7 287.7c-.04.04-.06.05-.09.06a.12.12 0 01-.07 0c-.02 0-.04-.02-.08-.06l-57.69-57.7c-.04-.03-.05-.05-.06-.07a.12.12 0 010-.07c0-.03.02-.05.06-.09L454.07 512l-287.7-287.7c-.04-.04-.05-.06-.06-.09a.12.12 0 010-.07c0-.02.02-.04.06-.08l57.7-57.69c.03-.04.05-.05.07-.06a.12.12 0 01.07 0c.03 0 .05.02.09.06L512 454.07l287.7-287.7c.04-.04.06-.05.09-.06a.12.12 0 01.07 0z"
                />
              </svg>
            </span>
          </span>
        </button>
@@ -465,17 +467,18 @@
            >
              <svg
                aria-hidden="true"
                data-icon="close"
                fill="currentColor"
+               fillRule="evenodd"
                focusable="false"
                height="1em"
                viewBox="64 64 896 896"
                width="1em"
              >
                <path
-                 d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
+                 d="M799.86 166.31c.02 0 .04.02.08.06l57.69 57.7c.04.03.05.05.06.08a.12.12 0 010 .06c0 .03-.02.05-.06.09L569.93 512l287.7 287.7c.04.04.05.06.06.09a.12.12 0 010 .07c0 .02-.02.04-.06.08l-57.7 57.69c-.03.04-.05.05-.07.06a.12.12 0 01-.07 0c-.03 0-.05-.02-.09-.06L512 569.93l-287.7 287.7c-.04.04-.06.05-.09.06a.12.12 0 01-.07 0c-.02 0-.04-.02-.08-.06l-57.69-57.7c-.04-.03-.05-.05-.06-.07a.12.12 0 010-.07c0-.03.02-.05.06-.09L454.07 512l-287.7-287.7c-.04-.04-.05-.06-.06-.09a.12.12 0 010-.07c0-.02.02-.04.06-.08l57.7-57.69c.03-.04.05-.05.07-.06a.12.12 0 01.07 0c.03 0 .05.02.09.06L512 454.07l287.7-287.7c.04-.04.06-.05.09-.06a.12.12 0 01.07 0z"
                />
              </svg>
            </span>
          </span>
        </button>
    at Object.<anonymous> (/work/cashtab/src/components/Configure/__tests__/Configure.test.js:39:18)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:218:40)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:66:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:389:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:475:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:133:12)

Each failure log is accessible here:
CashTab Unit Tests: Verify handleUpdateWallet() correctly initializes the active wallet
CashTab Unit Tests: Verify processChronikWsMsg() processes AddedToMempool events
CashTab Unit Tests: Without wallet defined
CashTab Unit Tests: Wallet without XEC balance
CashTab Unit Tests: Wallet with XEC balances
CashTab Unit Tests: Wallet with XEC balances and tokens
CashTab Unit Tests: Wallet with XEC balances and tokens and state field
CashTab Unit Tests: Wallet with BCH balances and tokens and state field
CashTab Unit Tests: Wallet without BCH balance
CashTab Unit Tests: Wallet with BCH balances
CashTab Unit Tests: Wallet with BCH balances and tokens

package-lock.json was corrupted somehow during uninstall/reinstall of local ecash-coinsect vs npm hosted one

reverting unrelated snapshot changes from package-lock.json patch, add script unit test to ecash-coinselect

Remove dead code now that coinselect throws errors instead of mysteriously returning undefined for inputs and outputs

Fabien requested changes to this revision.Sep 22 2023, 14:42

Let's not do it all at once: start with the lib overhaul, incrementally, then use it in cashtab.

Please close this diff, it has too much revisions already.

This revision now requires changes to proceed.Sep 22 2023, 14:42

To be split up into smaller diffs -- retiring this as proof of concept.

Upcoming stack

  • Take ecash-coinselect back to the studs
  • Implement ecash-coinselect as it is in this diff w/ version bump
  • New tx function in Cashtab, using ecash-coinselect
  • Implement new tx function in Cashtab