Repository navigation
Split Bitcoin wallets into eCash (ECX) - #6294
Conversation
28a76bd to
4209150
Compare
There was a problem hiding this comment.
Claude Code Review
Claude Code Review is paused for this repository because its GitHub organization is not linked to your Claude organization.
To turn it back on, one person needs both roles: owner of the GitHub organization (or the account owner, for a personal repository) and admin or owner of your Claude organization. If that is not you, pass this on to someone who is.
Open Organization settings, Git providers and click Link next to the GitHub organization's name. If it is not listed, click Enable GitHub integration or Connect your GitHub first, whichever the page shows.
New pull requests are then reviewed as before. To get a review on one that is already open, someone with write access can comment @claude review.
Tip: disable this comment in your organization's Code Review settings.
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
| const result = await stream.next() | ||
| const sweep: EdgeTransaction | undefined = | ||
| result.done === true ? undefined : result.value[0] | ||
| return sweep?.confirmations === 'confirmed' ? 'settled' : 'pending' |
There was a problem hiding this comment.
Warning: anything without a confirmed "Replay Protection Tx" reads as pending forever. That includes a sweep core never sent (app closed before the ECX wallet synced; see the EdgeApp/edge-core-js#749 review), a dropped or failed sweep, and an ECX wallet imported from the same key (isImportKeySupported: true), which never had a sweep. In each case the BTC wallet tells the user to wait for a confirmation that will never come, and polling never stops. This needs a recovery path (or a core-provided status) rather than an indefinite wait.
There was a problem hiding this comment.
The card now reads core's EcxProtection.json (EdgeApp/edge-core-js#749). A pending record shows a new message saying the transaction has not gone out yet and goes out once the eCash wallet syncs. A sent record keeps the wait-to-confirm message until that txid confirms. An ECX wallet without a record, such as one imported from the same key, shows no card; protecting imported wallets is a follow-up.
| wallet: EdgeCurrencyWallet | ||
| ): Promise<EcashSplitStatus> { | ||
| // An empty wallet has nothing to separate, though it may still be syncing: | ||
| if (wallet.balanceMap.get(null) === '0') return 'clear' |
There was a problem hiding this comment.
Warning: right after a split the ECX wallet has not synced. Its balance reads '0' and this returns clear. The card stays hidden during the window when a BTC send is most likely to replay, and it appears only after the balance syncs. Checking the ECX wallet's syncStatus.totalRatio before trusting a zero balance would cover it.
The same early return also means an emptied ECX wallet never reaches settled. The 15s poll then runs for as long as the BTC transaction list is open.
There was a problem hiding this comment.
The balance check is gone. The record says pending from the moment of the split, so the card shows while the ECX wallet syncs. An emptied wallet settles once its sweep confirms, or right away when its record says empty, which ends the poll.
| searchString: PROTECTION_TX_NAME, | ||
| firstBatchSize: 1 | ||
| }) | ||
| const result = await stream.next() |
There was a problem hiding this comment.
Suggestion: the stream is read once and never closed. With the 15s poll, each tick leaves another open streamTransactions iterator per matching ECX wallet over the core bridge. A stream.return?.() in a finally would release it.
There was a problem hiding this comment.
The lookup reads the stream with for await, which calls return() when it stops early. A test checks that the stream closes.
| // Transactions stream newest first, so this finds the latest sweep: | ||
| const stream = wallet.streamTransactions({ | ||
| tokenId: null, | ||
| searchString: PROTECTION_TX_NAME, |
There was a problem hiding this comment.
Suggestion: matching on the free-text name couples the GUI to an English string core happens to write. searchString also matches notes. A user who renames the sweep makes the card stick on pending, and a user tx with that text in its notes is mistaken for the sweep. A structured marker from core (e.g. savedAction or a wallet-level flag) would be sturdier.
There was a problem hiding this comment.
The sweep is now found by the txid core records, not by its name.
4209150 to
fa4e14c
Compare
fa4e14c to
65ea893
Compare
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
Without a default value, the hook ran the first refresh right away and also scheduled one after the delay, so two refresh loops ran side by side and every caller refreshed twice per delay. Unmounting cleared only one of the two timers, so the other still fired once. The info server refresh in Services and the Zcash migration status both start without a default value.
Render the menu option icons through VectorIcon instead of a direct AntDesign import.
Registers the ecashbitcoin and ecashbitcoinbetanet plugins, off unless the plugin config enables them, with UTXO currency info matching Bitcoin's. Betanet is a test network, so it also needs beta features, and production Bitcoin wallets never offer a split into it.
Splitting into eCash (ECX) sweeps the new wallet to itself, and until that sweep confirms a Bitcoin send can be replayed on ECX. edge-core-js records the sweep in the ECX wallet's EcxProtection.json. The Bitcoin wallet scene shows a warning while an ECX wallet with the same xpubs has a sweep that has not gone out yet or has not confirmed, and finds the sweep by the txid in that record.
Splitting a Bitcoin wallet into eCash (ECX) makes the new wallet sweep its funds to itself, which costs an ECX network fee, and until that sweep confirms a Bitcoin send can also move the ECX. The split button now explains this in a modal and only splits once the user confirms.
93ea39b to
076ed55
Compare


Description
Asana task
Lets Bitcoin wallets split into eCash (ECX), Paul Sztorc's Bitcoin hard fork, and warns the user while the split wallet is still exposed to replay.
ecashbitcoinandecashbitcoinbetanetplugins, off unless the plugin config enables them. Betanet also needs beta features, so production Bitcoin wallets never offer a split into it.EcxProtection.jsonedge-core-js keeps in the ECX wallet. The card says which, and finds the sweep by its recorded txid.useRefresherrunning two refresh loops at once when it starts without a default value, which doubled the info server and Zcash migration refreshes. The eCash warning uses its newisFinaloption to stop polling once every split wallet's sweep confirms.CHANGELOG
Does this branch warrant an entry to the CHANGELOG?
Dependencies
Requirements
If you have made any visual changes to the GUI. Make sure you have: