Skip to content

Add controller-specific seizure override for Securitize vaults - #434

Open
dglowinski wants to merge 1 commit into
developmentfrom
feat/securitize-seize-ignore-controller
Open

dglowinski wants to merge 1 commit into
developmentfrom
feat/securitize-seize-ignore-controller

Conversation

@dglowinski

Copy link
Copy Markdown
Collaborator

Summary

A controller whose account status check reverts can block governor seizure. Add seize(from, to, amount, ignoreController) so the governor can bypass the check for an explicitly named controller.

Changes

  • Skip requesting the source account's status check only when its sole enabled controller equals the nonzero ignoreController address. Mismatches, multiple controllers, and the zero address retain normal status checking; the three-argument overload uses the zero address.
  • Transfer shares internally while preserving allowances, prefix-balance accounting, recipient compliance, pause/freeze restrictions, governor authentication, reentrancy protection, and GovSeized events.
  • Leave checks queued by other EVC batch operations in force. Document that naming a legitimate lending controller can leave its debt undercollateralized and cause lender losses.

Test plan

  • Focused Securitize suite: 15 tests passed, including fuzzed subaccounts, transfer amounts, and allowances; matching and mismatched controllers; authorization; compliance; EVC routing; deferred and multiple-controller checks.
  • forge fmt --check on both changed Solidity files and git diff --check.
  • Full forge build --offline.
  • Non-fork suite using the CI path exclusions: 445 tests passed across 57 suites. Fork tests were excluded.
  • Compile the base and proposed vault/factory with identical settings to compare runtime and creation bytecode sizes; confirm the deployment sizes with forge build src/VaultFactory/ERC4626EVCCollateralSecuritizeFactory.sol --offline --optimizer-runs 10000 --sizes using separate output and cache paths.

Code size

Solidity 0.8.24, Cancun, optimizer enabled with 10,000 runs, matching the Securitize factory settings in script/interactiveDeployment.sh and script/utils/verifyContracts.sh. EIP-170 permits 24,576 bytes of runtime code.

Contract Base runtime PR runtime PR creation bytecode
Securitize collateral vault 19,520 19,842 21,699
Securitize collateral factory 23,860 24,196 24,387

Both runtime sizes remain below the limit: 4,734 bytes of headroom for the vault and 380 bytes for the factory. Both creation bytecodes are below the 49,152-byte EIP-3860 limit before constructor arguments.

The repository's default 20,000-run build produces a 21,750-byte vault and a 26,104-byte factory. The factory exceeds EIP-170 under those defaults, including on the base branch (25,588 bytes); deployment must use the existing Securitize-specific 10,000-run settings.

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — no PR-specific blocking findings

Reviewed head 2c98ce5e068b7985948bfde692737ed1de6e2127 against development (816c5943). This is a review-only COMMENT, not formal approval.

Scope and conclusions

  • Reviewed all three changed files: the Securitize vault, its tests, and docs/securitize-vault.md; traced the inherited ERC20 transfer/update path, EVC routing/authentication, deferred status-check handling, and existing deployment compiler settings.
  • The bypass requires a nonzero exact match to the source account's sole enabled controller. The legacy overload retains status checking. Previously queued EVC checks are not removed.
  • Moving directly through _transfer retains zero-address/insufficient-balance rejection and the Securitize _update prefix accounting, without modifying allowances. Governor authentication, recipient compliance, pause/freeze restrictions, and reentrancy protection remain on the shared overload.
  • No dependency, workflow, external-call destination, or privilege expansion beyond the explicitly documented governor seizure override was introduced.

Independent validation

  • forge test --match-path test/Vault/ERC4626EVCCollateralSecuritize.t.sol -vv: 15 passed, including 1,000 fuzz runs for subaccount/amount/allowance preservation.
  • forge build --offline: passed (compiler warnings).
  • forge fmt --check src/Vault/deployed/ERC4626EVCCollateralSecuritize.sol test/Vault/ERC4626EVCCollateralSecuritize.t.sol and git diff --check origin/development...HEAD: passed.
  • forge test --offline --no-match-path 'test/{HookTarget/HookTargetMarketStatus.t.sol,HookTarget/HookTargetStakeDelegator.t.sol,Liquidator/SBLiquidator.t.sol,OFT/OFTFeeCollectorFork.t.sol,OFT/OFTFeeCollectorGulperFork.t.sol,Swaps/MigrationHelperFork.t.sol,Swaps/Swaps1Inch.sol}': 443 passed, 2 failed across 57 suites. Both failing counterexamples also reproduce on base 816c5943 with forge test --offline --match-test 'test_GovernanceModifiers|test_redeem_zero_allowance':
    • ERC20SynthTest.test_GovernanceModifiers: expected revert not observed.
    • ERC4626EVCCollateralFreezableStdTest.test_redeem_zero_allowance: assertion failure.
      These are baseline failures in this local run, not regressions attributed to this PR. Hosted Foundry CI is successful.
  • forge build src/VaultFactory/ERC4626EVCCollateralSecuritizeFactory.sol --offline --optimizer-runs 10000 --sizes --out out-size --cache-path cache-size: passed. Vault runtime 19,842 bytes; factory runtime 24,196 bytes, leaving 380 bytes under EIP-170. Creation sizes are 21,699 / 24,387 bytes, respectively.

Documented operational boundaries

Naming a legitimate lending controller can remove debt-backing collateral and impose lender losses; the exact-address match is not evidence of maliciousness. This is the intended, explicitly documented governor capability, not a newly discovered bypass by an unprivileged user. The existing Securitize-specific 10,000-run deployment settings remain important.

Validation used the repository's local Securitize/controller fixtures and pinned EVC implementation. No live deployment, underlying compliance-service integration, or fork test was exercised.

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.

2 participants