Skip to content

feat(token): co-sign legal transfers - #262

Open
hpmaxi wants to merge 4 commits into
test/harness-wind-downfrom
feat/legal-transfer
Open

hpmaxi wants to merge 4 commits into
test/harness-wind-downfrom
feat/legal-transfer

Conversation

@hpmaxi

@hpmaxi hpmaxi commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Until now the compliance key alone could move any holder's shares, the vault's escrow included, and freeze the vault's address. A legal-order transfer now needs governance's signature in the same call, never moves shares out of or into the vault's address, and only lands on an allowlisted account. A recovery needs the same co-signature and goes only to the new address the identity verifier names. Both move wallet shares only; value the vault holds for a frozen holder waits for an unfreeze.

Changes

  • legal_transfer(from, to, amount, reference, operator): compliance asks, the token admin co-signs, two different accounts; publishes LegalTransfer with the order reference
  • forced_transfer is manager-only; the vault's escrow is unchanged
  • recover_balance needs the admin's co-signature and never moves shares out of or into the vault's address
  • Freezing the vault's address, fully or partly, is refused (VaultAddress); unfreezing it stays possible
  • health() reports vault_unfrozen, and the vault's finish_setup refuses while its address is frozen
  • The harness deploy checks vault_unfrozen; the docs describe the co-signature

Deviations

  • recover_balance also refuses the vault as the new account: OpenZeppelin's recovery copies a freeze onto it.
  • The self-co-sign test grants the role with grant_role during setup; this base does not refuse that grant yet.
  • The vault's frozen-address case joins the existing wiring tables as Miswire::VaultFrozen, frozen through the token before bind_vault, instead of a new test in controls.rs.
  • Missing-signature tests also show the call passing once the admin signs.
  • Also fixed docs the plan did not list: health table, admin panel, roles and TTL lists.

Acceptance criteria

  • legal_transfer needs the compliance authority and the admin as two different accounts in one call
  • It refuses the vault's address as source or destination, a destination that fails the identity check, and a missing or overlong reference; it publishes the reference
  • forced_transfer is manager-only; the vault's escrow still works
  • recover_balance needs the admin's co-signature and never moves the vault's balance
  • Freezing the vault's address, fully or partly, is refused
  • The vault's finish_setup refuses while its address is frozen

Test plan

Automated tests

  1. CARGO_TARGET_DIR=<repo>/target SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2=1 nix develop -c cargo test --locked -p share-token legal_transfer: 13 tests pass.
  2. CARGO_TARGET_DIR=<repo>/target SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2=1 nix develop -c cargo test --locked: the workspace passes (share-token 64, async-vault 370), including every_wiring_step_is_checked_before_setup_finishes and each_missing_wiring_step_shows_in_its_own_flag with the frozen vault.
  3. On a fresh local network: npm run deploy, then test:happy-path (24/24), test:guards (46/46) and test:wind-down (6/6). The deploy prints "vault_unfrozen":true.

Manual verification

On the same local network, a script signed as compliance: alone, the SDK asks for governance's signature; co-signed by governance, one share moved; from or to the vault, and freezing the vault, returned VaultAddress; compliance's forced_transfer returned Unauthorized.

Breaking changes

forced_transfer refuses the compliance role. On the next deployment the console's compliance transfer must call legal_transfer with governance's co-signature, and recovery needs it too. health() gains vault_unfrozen, and the token's spec gains legal_transfer, the LegalTransfer event and errors 7012, 7013 and 7015, so clients must be regenerated.

Checklist

  • Self-reviewed my own diff
  • Tests added or updated
  • Docs updated (if applicable)
  • No unrelated changes bundled in

Screenshots

None.

@vercel

vercel Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
strata-vault-kit-app Ready Ready Preview Oct 17, 2026 5:54pm UTC

Request Review

@hpmaxi
hpmaxi marked this pull request as ready for review October 17, 2026 18:05

This branch was successfully deployed

1 active deployment
Preview — 255cb4cf Deployed Oct 17, 2026 by vercel[bot]
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