Skip to content

feat: key merge voting and holder position migration - #1020

Merged
Chucks1093 merged 3 commits into
accesslayerorg:mainfrom
Emmazlee:fix/key-merge-vote-migrate-962
Oct 2, 2026
Merged

Chucks1093 merged 3 commits into
accesslayerorg:mainfrom
Emmazlee:fix/key-merge-vote-migrate-962

Conversation

@Emmazlee

Copy link
Copy Markdown
Contributor

Overview

creator-keys/src/acl_limits_merge_sunset.rs shipped only a placeholder key-merge flow: propose_key_merge stored a ratio and execute_key_merge flipped flags and returned the ratio. There was no way for source-key holders to vote, no threshold check, no balance migration and no source-key deprecation, so the merge was a no-op. This change builds the missing voting, migration and deprecation flow inside the existing module (the crate still has no matching lib.rs entrypoints) and reuses the protocol's real holder-balance storage.

Related Issue

#962 — Add on-chain key merge voting and execution with position migration.

Changes

  • [ADD] creator-keys/src/acl_limits_merge_sunset.rs — vote_on_merge(holder, source_key, approve) weights a source-key holder's vote by their liquid KeyBalance, replaces a previous vote by removing the old weight before adding the new one so no holder is double counted, and rejects non-holders and votes cast after execution.
  • [ADD] MergeVoteRecord and MergeMigrationEntry contract types, the MergeHolders / MergeVote / MergeMigrationLog keys in the module's existing EmwulrdDataKey namespace, and get_key_merge_proposal / get_merge_migration_log views.
  • [CHANGE] KeyMergeProposal now carries approval_threshold_bps, votes_for, votes_against and total_voted_weight.
  • [CHANGE] propose_key_merge takes the approval threshold and the source-holder set, validates the ratio/threshold ranges, rejects duplicate holders and refuses to overwrite an executed proposal.
  • [CHANGE] execute_key_merge validates the weighted approval share against approval_threshold_bps before touching state, then migrates every registered holder's liquid and staked positions to the target key at conversion_ratio_bps (target balances are additive), transfers the aggregate TotalStaked, stores the full migration log, deprecates the source key with the protocol-wide marker plus the module sunset status, and emits MergeExecuted with the ratio/counts and KeyDeprecated.
  • [ADD] Five #[test] cases covering weighted vote collection, non-holder rejection, vote switching without double counting, threshold failure with no state mutation, and the successful migration/deprecation path including the second-execution guard and invalid proposal inputs.

Verification Results

I fetched creator-keys/src plus the workspace manifests into a scratch tree and compiled it against the repo's pinned soroban-sdk 22.0.11 with cargo check --offline --tests and cargo test --offline --lib acl_limits_merge_sunset::test. Both succeed; the five new tests pass:

running 5 tests
test acl_limits_merge_sunset::test::propose_rejects_duplicate_holders_and_bad_parameters ... ok
test acl_limits_merge_sunset::test::changing_vote_replaces_weight_without_double_counting ... ok
test acl_limits_merge_sunset::test::merge_votes_use_liquid_source_balance_as_weight ... ok
test acl_limits_merge_sunset::test::execute_rejects_below_approval_threshold ... ok
test acl_limits_merge_sunset::test::execute_migrates_all_positions_and_deprecates_source ... ok

test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 378 filtered out

lib.rs was left untouched, and I did not run the crate's wider snapshot suite.

Acceptance Criteria Status
Votes collected correctly from source key holders ✅ merge_votes_use_liquid_source_balance_as_weight — weight equals the holder's liquid source-key balance
Execution rejected below vote threshold ✅ execute_rejects_below_approval_threshold — returns Unauthorized, balances untouched
All holder balances migrated at correct conversion ratio ✅ execute_migrates_all_positions_and_deprecates_source — liquid and staked moved at 50%
Source key deprecated atomically post-migration ✅ Same test asserts the deprecation marker and sunset status
Unit tests cover vote collection, threshold failure, and successful migration ✅ Five tests in acl_limits_merge_sunset::test

Closes #962

Add weighted holder voting, threshold validation, atomic balance migration and source-key deprecation to the key merge module.
@drips-wave

drips-wave Bot commented Sep 28, 2026

Copy link
Copy Markdown

@Emmazlee Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Chucks1093 pushed a commit that referenced this pull request Sep 30, 2026
…t budget

`cargo clippy --workspace --all-targets -- -D warnings` fails with
`this function has too many arguments (8/7)` at the test helper `propose`.

The helper mirrors the entrypoint's seven parameters and adds `contract_id`,
because each entrypoint runs in its own contract frame. Rather than allow the
lint, group the proposal under test - the two keys, the quorum and the holder
list - into a `MergeProposalSpec`, which brings the helper to four arguments
and leaves the entrypoint signature untouched.

Verified with `cargo clippy --workspace --all-targets -- -D warnings` and
`cargo test -p creator-keys` on the branch tree.
@Chucks1093
Chucks1093 merged commit b1019b4 into accesslayerorg:main Oct 2, 2026
1 check passed
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.

Add on-chain key merge voting and execution with position migration

2 participants