Skip to content

[DO NOT MERGE - hard drain] D-2.2 slice 4: remove ecdsaWalletRegistry handle + heartbeat callback#973

Draft
mswilkison wants to merge 3 commits into
extraction/frost-mirror-2026-05-26from
extraction/d2-2-slice4-DO-NOT-MERGE-2026-05-26
Draft

[DO NOT MERGE - hard drain] D-2.2 slice 4: remove ecdsaWalletRegistry handle + heartbeat callback#973
mswilkison wants to merge 3 commits into
extraction/frost-mirror-2026-05-26from
extraction/d2-2-slice4-DO-NOT-MERGE-2026-05-26

Conversation

@mswilkison

Copy link
Copy Markdown
Contributor

⚠️ DO NOT MERGE — hard drain

This PR must NOT merge until ECDSA wallet population reaches hard-drain state — every ECDSA wallet must be Closed or Terminated (per Wallets.WalletState enum). This is the final D-2.2 cleanup that structurally closes the ECDSA-wallet on-chain surface.

Drain prerequisite

Stricter than slice 2 (#972, which gates on no-challengeable-state). Slice 4 requires every ECDSA wallet to be in post-final-lifecycle state. After merge: no on-chain code path reads from ecdsaWalletRegistry; that registry can be deprecated entirely (off-chain decision).

Source-PR provenance

  • Source repository: tlabs-xyz/tbtc
  • Source PR: #455
  • Source PR HEAD (sourceCommit): b8fd667871c06d6c7e5ba30f1fa5789f582d2058
  • Source manifest drainGatedSlices entry: "D-2.2 slice 4"
  • Sibling FROST-base tag: frost-extraction-source-v1 at commit 52389bd5cc...

Files (2 total, both allowlisted-divergence)

File Change summary
solidity/contracts/bridge/Bridge.sol Removes __ecdsaWalletHeartbeatFailedCallback + ecdsaWalletRegistry handle reads (IDLE precheck etc.)
solidity/contracts/bridge/Wallets.sol Removes IDLE precheck against ecdsaWalletRegistry + notifyWalletHeartbeatFailed library function

⚠️ Diff scope notice

Same caveat as the slice 2 PR (#972) — this PR is opened against canonical main, NOT against the FROST mirror PR #971's branch. The visible diff includes BOTH:

  1. The full FROST extraction state (delivered by PR #971)
  2. The slice 4 deltas on top of Initial development setup #1

After PR #971 merges to canonical main, this PR should be rebased. The rebased diff will shrink to just the slice 4 deltas (2 files) — what actually needs review and dual signoff.

Verification (pre-merge per plan v38 §7.3)

  • Per-file SHA-256: sha256(file at this PR HEAD) == sha256(file at PR #455 HEAD = b8fd667871) for each file
  • Dual signoff required on each allowlisted-divergence entry per plan v38 §4.2:
    • Extraction lead (Maclane): pending; collect immediately before undraft
    • Canonical repo maintainer (Threshold): pending
  • Hard-drain confirmation (every ECDSA wallet Closed or Terminated via subgraph queries) required immediately prior to undraft. Maintenance lifecycle addendum records both signoffs + drain proof.

Plan context

This is 2 of 2 drain-gated DO-NOT-MERGE drafts in the FROST extraction:

  • Slice 2: PR #972 (slashWalletForFraud removal)
  • This PR: slice 4 (heartbeat callback removal)

Both block on operational drain. Slice 4's drain is strictly stronger than slice 2's. They can land independently in either order once their respective drain conditions are met.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8df0ef9a-3d93-4bb8-8141-93ce08d4309e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch extraction/d2-2-slice4-DO-NOT-MERGE-2026-05-26

Comment @coderabbitai help to get the list of available commands and usage tips.

mswilkison added a commit that referenced this pull request May 26, 2026
Resolves canonical CI failures on PR #971 / #972 / #973. Root cause:
the umbrella tlabs-xyz/tbtc carries a TBTCVaultMigration feature
(part of the account-control / covenant stack) that does NOT exist
on canonical threshold-network/tbtc-v2 main. Bridge.sol's mirror
brings dependencies on ITBTCVaultMigrationDebt + ITBTCVaultMigrationSweepHook
which 404 on canonical compile.

Per the standing mandate ("keep account-control / AC watchdog /
covenant work out of this stack"), the migration-debt surface must
be stripped from the canonical mirror rather than ported as a
prerequisite. This is an allowlisted-divergence on Bridge.sol +
related files, not a mirror.

Migration-debt strip (allowlisted-divergence, 4 files):
- Bridge.sol: remove ITBTCVaultMigrationDebt import; 3 errors
  (PreviousMigrationDebtVaultIsZero, PreviousMigrationDebtVaultMismatch,
  MigrationDebtVaultUnchanged); MigrationDebtVaultUpdated event;
  the 2 migration-debt guards in setVaultStatus (no-debt + canonical-
  vault-protection); setMigrationDebtVault, rotateMigrationDebtVault,
  _hasOutstandingMigrationDebt functions; migrationDebtVault() getter.
- BridgeState.sol: remove migrationDebtVault storage field; bump
  __gap from uint256[39] to uint256[40] to preserve total slot count.
- BridgeGovernance.sol: remove setMigrationDebtVault + rotateMigrationDebtVault
  governance wrappers.
- DepositSweep.sol: remove ITBTCVaultMigrationSweepHook import; remove
  MigrationSweepCallbackFailed + MigrationSweepCallbackRetryFailed
  events; remove notifyMigrationSweepCallback call site from submit-
  DepositSweepProof flow; remove full notifyMigrationSweepCallback
  function (47 lines).

Storage layout snapshot:
- Bridge.storage-layout.json: regenerated to match the post-strip
  layout. migrationDebtVault (slot 30) removed. 11 subsequent members
  shifted down by 1 slot. __gap type updated from t_array(t_uint256)39
  to t_array(t_uint256)40 (now at slot 38). t_array(t_uint256)39_storage
  type definition removed (no remaining references). Total struct
  numberOfBytes unchanged at 2496 (slot count preserved).

Storage-layout invariant property: removal restores parity with
canonical's deployed Bridge (which never had migrationDebtVault),
so the canonical upgrade path stays safe. The forbidden hazard is
ADDING fields that mismatch a deployed slot — which is what the
unstripped mirror would do.

TS test vector path normalization (path-relative class of bug,
caught by canonical's typescript-build-and-test):
- test/bridge/Bridge.P2TRFrauds.test.ts: docs/frost-migration/test-
  vectors/p2tr-signature-fraud-v0.json -> docs/test-vectors/p2tr-
  signature-fraud-v0.json + path depth ../../../../ -> ../../../
- Same fix applied to: CheckBitcoinBIP340Sigs.test.ts, CheckBitcoinBIP341
  Sighash.test.ts, P2TRSignatureFraudChallenge.test.ts,
  CheckBitcoinP2TRSignatureFraud.test.ts.
- WalletPubKeyHashDerivationVectors.test.ts: path depth
  ../../../../docs/test-vectors/... -> ../../../docs/test-vectors/...

Doc comment path normalization:
- test/integration/utils/frost-wallet-registry.ts: docs/frost-
  migration/ -> docs/rfc/frost-migration/ (canonical RFC placement).
- test/frost-registry/FrostWalletRegistry.Permissions.test.ts: same.

Prettier auto-fixes (root-level + typescript-level prettier --write,
config: @keep-network/prettier-config-keep):
- typescript/src/lib/bitcoin/address.ts, src/services/maintenance/
  p2tr-signature-fraud.ts, test/data/bitcoin.ts, test/services/
  p2tr-signature-fraud.test.ts, test/utils/mock-bridge.ts.
- services/watchtower/{src,test}/**/*.ts (13 TS files).
- typescript/scripts/refund.sh.
- docs/rfc/frost-migration/*.md (6 RFC docs).
- docs/test-vectors/*.json (2 vector files).
- services/watchtower/README.md.
- services/watchtower/tsconfig.{json,test.json}.

Manual JSDoc additions to satisfy canonical's valid-jsdoc eslint
rule (umbrella's eslint config didn't enforce it; canonical does):
- bridge.ts parseWalletDetails: walletID param.
- p2tr-signature-fraud.ts 6 functions: parseP2TRKeyPathWitness-
  Signature, extractP2TRKeyPathInputWitnessSignature, extractP2TR-
  WalletInputWitnessCandidates, computeP2TRWalletInputWitnessObservation
  ID, computeP2TRSignatureFraudBridgeChallengeIdentity, computeP2TR-
  SignatureFraudDraftChallengeIdentity. Each: @param entries for
  every parameter + @returns description.

Verified locally before push:
- prettier --check . from root: clean.
- prettier --check . in typescript/: clean.
- eslint src/**/*.ts test/**/*.ts in typescript/: 0 errors.

Manifest update will follow in a stacked PR on tlabs-xyz/tbtc#10
that reclassifies Bridge.sol, BridgeState.sol, BridgeGovernance.sol,
DepositSweep.sol, and Bridge.storage-layout.json from `mirror` to
`allowlisted-divergence` with their new expectedTargetSha256 values.
Source tag will be re-signed against the new umbrella HEAD post-merge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mswilkison mswilkison changed the base branch from main to extraction/frost-mirror-2026-05-26 May 27, 2026 16:38
@mswilkison mswilkison force-pushed the extraction/d2-2-slice4-DO-NOT-MERGE-2026-05-26 branch from da5c75c to 1dad2d6 Compare May 27, 2026 17:57
mswilkison added a commit that referenced this pull request May 27, 2026
The mirror workflow (umbrella tlabs-xyz/tbtc → canonical
threshold-network/tbtc-v2 + threshold-network/keep-core) is
retired as of 2026-05-27. Canonical is now source of truth for
all FROST/Schnorr migration work and D-2.2 follow-ups.

Replace the 1035-line external-repository-tracking.md (which
recorded the mirror direction's per-PR state and "do not mirror
in threshold-network/tbtc-v2" constraint) with a shorter
notice that:

- Records the pivot and date
- Documents what the change means in practice for contributors
  (no manifest tracking, no dual-signoff, plain conventional
  commit prefixes going forward, etc.)
- Lists what's in vs out of canonical scope explicitly
  (account-control, vault-migration-debt, covenant, PSBT covenant
  remain explicitly out of scope and live in a separate effort)
- Lists in-flight PRs at the time of the pivot (#971, #972, #973,
  keep-core companions) so reviewers picking up where this left
  off know what's already shipping
- Preserves a historical reference for the phases that landed via
  the mirror workflow (A, B-1, B-1.5, C-1, C-2, D-1, D-2.1, D-2.2
  slice 1) and the ones still pending (B-2, D-2.2 slices 2+4)

The full historical mirror-tracking content is preserved in git
history (last in-tree state at commit e37051d). The "extraction:"
commit prefixes already merged are durable historical artifacts
and stay as-is.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mswilkison mswilkison force-pushed the extraction/d2-2-slice4-DO-NOT-MERGE-2026-05-26 branch 2 times, most recently from 6793e8c to f459ff5 Compare May 27, 2026 21:35
@mswilkison mswilkison force-pushed the extraction/d2-2-slice4-DO-NOT-MERGE-2026-05-26 branch from f459ff5 to f41718b Compare May 27, 2026 21:37
…26' into pr973-conflicts

# Conflicts:
#	solidity/contracts/bridge/BridgeState.sol
#	solidity/contracts/bridge/Wallets.sol
#	solidity/test/bridge/Bridge.Wallets.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant