feat(kaspa): add migration command for escrow key rotation#433
Closed
feat(kaspa): add migration command for escrow key rotation#433
Conversation
Co-authored-by: Danil Nemirovsky <4614623+ameten@users.noreply.github.com>
Co-authored-by: Danil Nemirovsky <4614623+ameten@users.noreply.github.com>
…7073) Co-authored-by: Danil Nemirovsky <4614623+ameten@users.noreply.github.com>
…e-xyz#7079) Co-authored-by: Danil Nemirovsky <4614623+ameten@users.noreply.github.com>
…e (with help of claude) [NO BUILD]
…odulequeryClient interface
This reverts commit 650f253.
This reverts commit be1040a.
chore: fixed cargo warning
refactor(solana): atomic warp route deployment
* claude: refactor(kaspa): cleanup confirmation validator - Remove stale FIXME comment about address validation. Address validation is already performed during withdrawal signing (withdraw.rs:376-394). The confirmation validator trusts that withdrawals were properly validated at signing time. - Extract proto_to_outpoint helper function to DRY out duplicated TransactionOutpoint conversion code. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * claude: simplify proto_to_outpoint by removing field_name arg 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Extract duplicate output pair matching logic into `extract_output_pair` helper function. Both `prepare_next_iteration_inputs` and `create_inputs_from_sweeping_bundle` had identical pattern matching to identify escrow vs relayer outputs from a PSKT with exactly two outputs. The helper now returns an `OutputPair` struct containing both outputs with their indices. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The Foo(String) variant in HyperlaneKaspaError is never used anywhere in the codebase - only defined. Remove it to reduce dead code. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Extract shared HyperlaneMessage field validation into `validate_hl_message_fields` function in error.rs. Both deposit.rs and withdraw.rs MustMatch structs now use this shared function instead of duplicating the same validation logic. Also removes unused `enable_validation` field and `set_validation` method from deposit MustMatch (dead code that was never called). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add hex_to_kaspa_hash utility to dym-kas-core (dymension/libs/kaspa/lib/core) as a shared Kaspa hash conversion utility. Updates three call sites: - kas_validator/confirmation.rs - kas_relayer/confirm/confirmation.rs - kas_relayer/confirm/confirmation_test.rs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…#422) Remove redundant 'kas_' prefix from module names since they're already inside the dymension-kaspa crate. This improves code clarity without changing functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…rchain_gas_paymasters (#423) Update code to use the plural Vec<H256> field name that was changed in CoreContractAddresses. The scraper now uses .first().cloned().unwrap_or_default() to get the first IGP address from the array. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…#424) * claude: feat(kaspa): unify validator config into single kaspaValidators array Replace three separate comma-separated config fields with a single array of validator objects: Before: - validatorHosts: "host1,host2,..." - validatorIsmAddresses: "addr1,addr2,..." - validatorPubsKaspa: "pub1,pub2,..." After: - kaspaValidators: [ {host: "host1", ismAddress: "addr1", escrowPub: "pub1"}, ... ] This eliminates the implicit ordering requirement between separate fields and keeps related validator data together. The RelayerStuff struct now stores the unified Vec<KaspaValidatorInfo> directly instead of parallel vectors. Closes dymensionxyz/hyperlane-deployments#64 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * claude: fix(kaspa): sort signatures by ISM address for Hub ISM verification The Hub ISM requires signatures to be in lexicographic order of validator ISM addresses. This commit: - Updates collect_with_threshold to return (index, value) pairs - Sorts deposit signatures by recovered signer address - Sorts confirmation signatures by config ISM address (using index lookup) - Adds documentation about config ordering requirements - Adds warning logging for invalid ISM address parsing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
) * claude: feat(kaspa): add migration mode config and guards for key rotation Add ValidationConf fields: - migration_target_address: when set, enables migration mode - previous_escrow_address: for confirmation across escrow boundary Add is_migration_mode() helper and guard checks in handlers: - respond_validate_new_deposits: returns error in migration mode - respond_sign_pskts: returns error in migration mode - confirmation endpoint remains enabled for migration Config parsing updated to support: - migrationTargetAddress JSON field - previousEscrowAddress JSON field Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * claude: refactor(kaspa): remove redundant previous_escrow_address During migration, the current escrow config IS the old escrow. For confirmation boundary crossing, use migration_target_address as the new escrow instead of a separate previous_escrow_address. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * claude: refactor(kaspa): rename validation toggles and remove unused config - Rename deposit_enabled -> validate_deposits - Rename withdrawal_enabled -> validate_withdrawals - Rename withdrawal_confirmation_enabled -> validate_confirmations - Remove unused previousEscrowAddress from config parsing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* claude: feat(kaspa): add migration TX validation and signing endpoint Add /sign_migration endpoint for validators to sign migration PSKTs during key rotation. The endpoint: - Only accepts requests when migration mode is active - Validates that PSKT spends from current escrow inputs - Validates all outputs go to configured migration_target_address - Signs escrow inputs with validator's Kaspa key Also bumps hyperlane-cosmos-rs to include MigrationFxg proto. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * claude: rewrite migration validation with proper security checks Migration validation now implements all requirements from issue #192: - Query hub for current anchor via outpoint() and verify PSKT spends it - Query Kaspa for ALL escrow UTXOs and verify PSKT spends ALL of them - Verify PSKT contains ONLY expected inputs (escrow UTXOs + hub anchor) - Verify exactly ONE output to migration target address - Verify payload is empty MessageIDs (no withdrawals during migration) - Validate output amount doesn't exceed input amount Also: - Add parsed_migration_target() to ValidationConf for encapsulated parsing - DRY escrow_input_selector() and calculate_escrow_input_sum() in withdraw.rs - Pass hub_rpc and kaspa_grpc to migration validation in server.rs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * claude: fix migration validation critical issues Addresses review feedback: 1. Allow relayer fee inputs - removed "unexpected input" rejection since relayer needs to provide inputs to pay transaction fees 2. Verify escrow funds 100% preserved - now checks escrow_input_sum == output instead of output <= total_inputs (uses EscrowAmountMismatch error) 3. Verify UTXO amounts against Kaspa - query now returns amounts, and we verify each PSKT input amount matches what Kaspa reports for that outpoint 4. Fail on missing UTXO entries - now returns error instead of silently defaulting to 0 with map_or() 5. Use calculate_escrow_input_sum() from withdraw.rs for DRY escrow sum Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * claude: extract query_hub_anchor to ops/withdraw.rs DRY improvement - extracted hub anchor query logic: - Added parse_hub_outpoint() helper for outpoint conversion - Added query_hub_anchor() that uses withdrawal_status(vec![], None) - Updated filter_pending_withdrawals() to use parse_hub_outpoint() - Migration validation now uses shared query_hub_anchor() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * claude: refactor migration validation and DRY key loading - Rename sign_withdrawal_fxg to sign_pskt_bundle (serves both uses) - Extract load_keypair() method on KaspaEscrowKeySource to DRY key loading - Allow relayer change outputs in migration validation (same pattern as withdrawals) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * claude: revert unintended sealevel formatting changes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add relayer-side migration flow that: - Fetches all UTXOs from current escrow - Builds migration PSKT transferring funds to new escrow - Collects signatures from validators via get_migration_sigs - Combines bundles using multisig threshold - Finalizes and broadcasts migration transactions Also adds: - ValidatorsClient.get_migration_sigs() for collecting validator signatures - request_sign_migration_bundle() HTTP client function - finalize_migration_txs() for migration transaction finalization - Makes combine_all_bundles() public for reuse Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use imported PopulatedInput type from dym_kas_core::pskt - Use PopulatedInputBuilder instead of manual construction (fixes sequence value) - Consolidate create_pskt with optional payload (removes duplicate function) - Remove redundant threshold check (enforced by collect_with_threshold) - Remove unnecessary Arc clone Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add migrateEscrowTo setting that enables migration mode. When set, the relayer executes escrow key migration to the specified Kaspa address and exits instead of running the normal relayer loop. Usage: HYP_RELAYER_MIGRATEESCROWTO="kaspa:qz..." ./relayer Changes: - Add migrate_escrow_to field to RelayerSettings - Add migration check at start of Relayer::run() - Add run_escrow_migration() method - Refactor execute_migration to take &KaspaProvider - Re-export KaspaAddress from dymension_kaspa Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move the migration target address from RelayerSettings to the Kaspa-specific RelayerStuff config object. This is the proper location since migration is Kaspa-specific functionality. Changes: - Add migrate_escrow_to to RelayerStuff in conf.rs - Parse migrateEscrowTo in connection_parser.rs - Update relayer to read from KaspaProvider.must_relayer_stuff() - Remove hacky migrate_escrow_to from RelayerSettings Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract get_migration_target() helper and pass target address as parameter to run_escrow_migration() to eliminate duplicate lookups and reduce nesting. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix PR #432 migration construction to match PR #431 validation: 1. Payload: Use MessageIDs::new(vec![]).to_bytes() instead of None - Validation expects empty MessageIDs protobuf, not missing payload 2. Fee handling: Add relayer fee inputs and change output - Kaspa requires non-zero fees (fee = inputs - outputs) - Escrow funds are 100% preserved (escrow_sum == target_output) - Relayer pays fees from their own UTXOs with change returned 3. Hub anchor verification: Check hub anchor is among escrow UTXOs - Query hub for current anchor before building PSKT - Fail early if state is stale (anchor not in escrow UTXOs) The migration PSKT now: - Inputs: all escrow UTXOs + relayer fee UTXOs - Outputs: migration target (escrow_sum) + relayer change (relayer_sum - fee) - Payload: empty MessageIDs serialized as protobuf Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Validators only sign escrow inputs, but the relayer fee inputs were left unsigned, which would cause a panic at runtime during finalization. Add sign_relayer_fee helper to sign relayer inputs after collecting validator signatures, matching the withdrawal flow pattern. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Author
|
Closing: duplicate of #432, accidentally opened against |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--kaspa.migrateEscrowToto trigger escrow key migrationTest plan
🤖 Generated with Claude Code