Skip to content

Access Control

Function Permissions

Function(s) Caller Notes
deposit Any address Open to all; no pause check
requestWithdraw Any address Shares pulled from msg.sender; no pause check
cancelWithdraw Original requester only queue[requestId].owner must equal msg.sender; no pause check
processWithdrawals Keeper only require(msg.sender == keeper) — explicit on-chain check
setKeeper Governance only require(newKeeper != address(0)); emits KeeperUpdated
setOperator Governance only require(newOperator != address(0)); emits OperatorUpdated
proposeGovernance Governance only Sets pendingGovernance; emits GovernanceProposed
acceptGovernance pendingGovernance address only Completes transfer; emits GovernanceTransferred
openPosition Operator only Hot-wallet role — multisig not required
markSettling Operator only Hot-wallet role
closePosition Operator only Hot-wallet role
writeOff Operator only Hot-wallet role
rebasePosition Operator only Hot-wallet role
reclaimSlot Operator only Hot-wallet role
emergencyLiquidate Governance only System must be paused — enforced on-chain

Role Architecture

The implementation uses three roles instead of the original two:

Role Address Scope
governance Multisig Role rotation (setKeeper, setOperator), governance transfer, emergency liquidation
operator Hot wallet All position lifecycle management (openPosition through reclaimSlot)
keeper Bot Queue processing (processWithdrawals) only

The operator role allows routine position management from a hot wallet without exposing the governance multisig key for daily operations. Using the same address for both governance and operator collapses to a two-role model equivalent to the original spec.

Governance can rotate the operator at any time via setOperator(address).

Governance Transfer

Governance is transferred via a two-step pending/accept pattern:

  1. Current governance calls proposeGovernance(newAddress) — sets pendingGovernance
  2. The proposed address calls acceptGovernance() — completes the transfer

This prevents fat-finger transfers to wrong addresses. There is no enforced time delay between proposal and acceptance. The multisig process provides the equivalent governance control.

No mandatory time delay

A compromised governance key can transfer in a single block if the attacker also controls the target address. Multisig governance with multiple required signers is essential.

Governance Centralization

MVP Governance Risk

The operator address has broad power over position lifecycle but cannot change system parameters or rotate roles. Governance retains exclusive control over role rotation and emergency liquidation. For later versions, consider: - Timelocks on openPosition and rebasePosition - Immediate execution only for writeOff (which can only decrease NAV, never increase it — safe to allow without delay) - Multi-party signing thresholds for the operator role

Keeper Role

The processWithdrawals keeper is distinct from both governance and the operator. It is a hot-wallet or automated bot address that processes the redemption queue. Separation ensures that:

  • The keeper cannot alter positions or NAV
  • A compromised keeper can only process legitimate queued withdrawals (net neutral to the vault)
  • Governance retains exclusive control over capital deployment and role rotation

Security Implications

  • Write-off can only decrease NAV — conservative by design and safe to execute immediately
  • emergencyLiquidate is the only function that sells assets at market price; it is guarded by the on-chain pause check and governance authorization
  • rebasePosition can only move entry price downward (enforced) — it cannot inflate NAV
  • Governance transfer requires the pending address to accept — prevents one-step handoff to a wrong address