Skip to content

DepositContractCTN

Source: DepositContractCTN.sol in /Users/marcos/Desktop/centurion_phase1_upgradeable_refactor.

DepositContractCTN is the Phase-1 validator deposit entrypoint. It preserves the deposit-contract interface shape (deposit, get_deposit_root, get_deposit_count, supportsInterface) while adding Centurion-specific admission and custody checks before a validator can enter the system.

Current refactor correction

The current source has no baselineVaultFactoryFrozen, no freezeBaselineVaultFactory, no setBaselineVaultFactory, no setBaselineVaultRuntimeCodehash, no phase1CustodyChecksEnabled, no pubkeyAllowlistEnabled, no pubkeyAllowlistDisabledForever, and no ownerOnlyDepositorEnabled. Older handbook text that treated those as live controls was stale.

Implementation Metadata

Item Source value
Contract kind CENTURION_KIND_DEPOSIT
Implementation version DepositContractCTNUpgradeableV2
Economic policy hash label EFFECTIVE_BALANCE_COVERAGE_HYBRID
Upgrade shape Transparent proxy implementation using CenturionInitializable

Control Planes

The deposit path has four separate safety layers:

  1. Upgrade governance decides which implementation code is official. The live deposit proxy, factory proxy, controller proxy, claim-gatekeeper proxy, and vault beacon must satisfy CenturionUpgradeGovernor policy assertions.
  2. Deposit permissioning decides who may submit a deposit. The current source always requires an allowlisted intent keyed to the caller.
  3. Custody and route safety prove the withdrawal credentials route to a factory-registered Centurion vault with the expected beacon, controller, exit-request contract, and metadata.
  4. Economic and claim safety proves the target vault is deposit-ready through controller readiness data, reserve coverage, schema versions, risk state, trigger state, and claim-gatekeeper coherence.

Do not merge these into one operational question. A deposit can be permissioned but unsafe, or governance-approved but not permissioned for a specific depositor.

Required phrase Source-grounded boundary
Upgrade governance Governor policy assertions decide whether code and beacon targets match the expected policy.
Deposit permissioning allowlistAdmin and intent maps decide whether this sender may attempt this deposit.
Custody/readiness Baseline route checks decide whether this validator vault path is safe enough to accept funds.
Economic/claim safety Readiness and accounting checks decide whether the later claim and settlement assumptions are safe.

Key State

State Meaning Operational implication
depositCount Number of accepted deposits. Must increment exactly once after successful merkle insertion.
branch, zeroHashes Deposit tree state. Supports deposit-root compatibility checks.
allowlistAdmin Only account that can add/remove admission intents. Should be a hardened admission Safe, not an EOA.
pendingAllowlistAdmin Two-step allowlist-admin transfer target. Requires explicit acceptance; old intents are invalidated on acceptance.
allowlistEpoch Monotonic epoch included in intent hashes. Changes on allowlist-admin transfer, invalidating stale intents.
allowedDeposits Active intent map. Must contain the exact hash for pubkey, credentials, amount, caller, and epoch.
consumedIntents One-way replay-prevention map. A consumed intent cannot be re-allowlisted.
baselineVaultFactory and metadata hashes Factory and static configuration captured during initialization. Every deposit rechecks live factory/controller metadata against these values.
baselineUpgradeGovernor, baselineVaultBeacon Governance and beacon anchors. Every deposit rechecks live policy registry and beacon authority.
phase1ValidatorActivated One-time latch per validator pubkey hash. Prevents duplicate Phase-1 activation for the same pubkey.

Public Entry Points

Function Caller Effect
initialize(...) Deployment initializer Sets allowlist admin and stores validated baseline references.
deposit(...) Authorized depositor from intent hash Performs format, amount, custody, readiness, intent, root, and merkle checks.
addAllowedDeposit, addAllowedDeposits allowlistAdmin Adds default 32 CTN intents for the current admin as depositor.
addAllowedDepositFor, addAllowedDepositsFor allowlistAdmin Adds explicit amount/depositor intents.
removeAllowedDeposit, removeAllowedDepositFor allowlistAdmin Clears active intents without marking them consumed.
isAllowedDepositIntent, isAllowedDepositIntentFor Anyone Reads active intent status.
transferAllowlistAdmin, acceptAllowlistAdmin, cancelAllowlistAdminTransfer Current or pending allowlist admin Two-step admission-admin rotation; acceptance increments allowlistEpoch.
get_deposit_root, get_deposit_count, supportsInterface Anyone Deposit-contract compatibility views.

Deposit Path

  1. Validate pubkey length (48), withdrawal-credentials length (32), and signature length (96).
  2. Require msg.value >= 1 ether, exact gwei granularity, and amount that fits uint64.
  3. Run _enforcePhase1CustodyBaseline; current Phase-1 source requires exactly 32_000_000_000 gwei.
  4. Reject a pubkey hash already latched in phase1ValidatorActivated, then latch it.
  5. Compute intent hash as keccak256(abi.encode(pubkey, withdrawal_credentials, amountGwei, msg.sender, allowlistEpoch)).
  6. Require allowedDeposits[intentHash] == true.
  7. Clear allowedDeposits[intentHash], set consumedIntents[intentHash] = true, and emit consumption events.
  8. Recompute the deposit data root and reject mismatches.
  9. Emit DepositEvent, increment depositCount, and insert the leaf into the merkle tree.

Replay and sender binding

The authorized depositor is part of the intent hash. A relayer, operator, or Safe module cannot substitute itself for the intended caller unless the allowlist admin created an intent for that exact address.

Custody Baseline Checks

_enforcePhase1CustodyBaseline proves all of the following before a deposit is accepted:

  • baseline factory is configured;
  • amount is exactly 32 CTN in gwei;
  • withdrawal credentials are canonical execution credentials (0x01 plus zero padding and the vault address);
  • factory metadata matches stored factoryConfigHash, moduleSetHash, immutableConfigHash, address-derivation version, controller, and exit-request contract;
  • upgrade governor and vault beacon match stored baseline addresses;
  • vault beacon authority is the upgrade governor;
  • governor policy assertions pass for deposit, factory, controller, claim gatekeeper, and withdrawal-vault beacon;
  • treasury router bootstrap is closed;
  • vault is factory-registered and has the expected beacon-proxy runtime code hash;
  • vault metadata matches pubkey hash, withdrawal credentials, config hash, derivation version, exit-request contract, and controller;
  • controller readiness is well-formed, current enough, policy/schema matched, reserve-backed, beneficiary-initialized, trigger-armed, and in a safe running risk/claim state.

Removed False-Freeze Model

The current refactor deliberately removed the old deposit-side false-freeze surface. CenturionUpgradeGovernor.finalFreeze still exists as optional emergency machinery for registered beacons, but deposits no longer require finalFrozen and no deposit function reads it as a precondition. The safety boundary is now honest upgradeability plus live registry assertions, not a deposit-local claim that the baseline is frozen.

Operational Monitoring

Monitor:

  • DepositIntentAllowedFor, DepositIntentRemovedFor, DepositIntentConsumedFor;
  • AllowlistAdminTransferStarted, AllowlistAdminTransferred, AllowlistAdminTransferCancelled;
  • BaselineConfigured, BaselineMetadataConfigured;
  • DepositEvent;
  • governor events for registered target changes, queued upgrades, executed upgrades, and final freeze.

Evidence To Archive

For every production deposit, archive the pubkey, withdrawal credentials, authorized depositor, amount, allowlistEpoch, intent transaction, deposit transaction, DepositEvent, factory vault mapping, controller readiness response, and governor policy assertion outputs for all baseline components.