Skip to content

[design] Unify DVT crypto layer (AAStarValidator) with SuperPaymaster economic layer — stake-gated, operator-bound registration #321

Description

@jhfnetboy

Context — two DVT contract systems that don't talk to each other

Today the DVT has two independent, disconnected on-chain authorization systems:

AAStarValidator (YetAnotherAA-Validator) — crypto layer DVTValidator + Registry + GTokenStaking (SuperPaymaster) — economic layer
Identity key nodeId (bytes32) + BLS G1 pubkey operator address (EOA) + ROLE_DVT + GToken stake
Stores registeredKeys[nodeId]→pubkey, isRegistered[nodeId]no operator, no stake isValidator[address], GToken lock, role
Register registerPublicKey(nodeId, pubkey)no stake gate (deployed AAStarBLSAlgorithm is onlyOwner) addValidator(address)checks Registry.hasRole(ROLE_DVT) + locked stake ≥ minStake
Verify verifyAggregateSignature(nodeIds, sig, msgPoint) — checks isRegistered only, no stake/liveness _requireActiveValidator — real-time role+stake liveness on every consensus call
Job who can co-sign + verify the aggregate BLS signature who staked + slashing + liveness

The problem is not overlap/override — it's a break. The signing identity
(nodeId+pubkey in AAStarValidator) and the economic identity (address+stake in
SuperPaymaster) are never bound to each other. Consequences:

  • A BLS pubkey can be registered in AAStarValidator with zero stake — the signing
    key has no skin in the game.
  • An operator can stake in SuperPaymaster with no effect on who can actually co-sign.
  • Slashing can't punish a misbehaving signing node: DVTValidator doesn't know which
    nodeId belongs to which operator address.
  • The production signing/verification path (dvt nodes → registerPublicKey
    verifyAggregateSignature) is not connected to the economic layer at all.

Business goal

  1. Single stake source of truth — GToken staked under ROLE_DVT in the SuperPaymaster
    Registry/GTokenStaking is the only place stake is managed. Every other contract
    reads it, never re-implements it.
  2. Bind signing ↔ stake — a nodeId/pubkey is tied to a staked operator, so
    co-signing rights require economic backing and a misbehaving signer can be slashed
    through its operator.
  3. Permissionless self-registration — an operator can stake + register their own DVT
    node without owner approval, with an owner toggle so we can bootstrap in a
    permissioned (onlyOwner) mode first and flip to permissionless when ready.
  4. Keep the hot verification path cheap — no per-signature cross-contract reads.

Technical plan (proposed — to be challenged/finalized)

Bind by operator address; defer stake to SuperPaymaster; keep pubkey local.

YetAnotherAA-Validator — AAStarValidator

  • Add mapping(bytes32 => address) public nodeOperator; — the operator that owns a nodeId.
  • registerPublicKey(bytes32 nodeId, bytes pubkey) called by the operator
    (msg.sender):
    • record nodeOperator[nodeId] = msg.sender.
    • stake gate (when enabled): require
      Registry.hasRole(ROLE_DVT, msg.sender) and
      GTokenStaking.roleLocks(msg.sender, ROLE_DVT).amount ≥ Registry.getRoleConfig(ROLE_DVT).minStake.
    • toggle: bool public requireStake (owner-settable). false → bootstrap
      (onlyOwner registers, as today). true → permissionless-but-staked. This is the
      ①stake-check + ②toggle asked for.
  • Store the SuperPaymaster Registry address (owner-settable), read-only.
  • (Optional, later) verifyAggregateSignature adds a real-time liveness read per
    participating operator — off by default to keep gas/coupling low; discuss.

SuperPaymaster — Registry / GTokenStaking / DVTValidator

  • Confirm/keep the read interfaces the crypto layer needs: Registry.hasRole,
    Registry.getRoleConfig(ROLE_DVT).minStake, Registry.GTOKEN_STAKING(),
    GTokenStaking.roleLocks(user, roleId). (All appear to exist as of DVTValidator 0.6.0.)
  • Slashing linkage: to slash a misbehaving signer, DVTValidator needs
    nodeId → operator. Options: (a) AAStarValidator emits NodeBound(nodeId, operator)
    and off-chain relays to a slash proposal; (b) a small view/callback. Discuss which.
  • ROLE_DVT = keccak256("DVT") — align the roleId constant across both repos.

Roles / responsibilities after unification

  • SuperPaymaster = economic/governance single source of truth: GToken stake,
    ROLE_DVT, slashing, liveness.
  • AAStarValidator = cryptographic layer: BLS pubkey registry + aggregate
    verification; registration reads SuperPaymaster for the stake gate and binds
    nodeId → staked operator.
  • Link = operator address, stored per nodeId.

Why not fully consolidate into SuperPaymaster

verifyAggregateSignature is the hot path (called per UserOp). Keeping pubkeys local
avoids a cross-contract read per signature (gas + tight coupling). We read the economic
layer once at registration, not per verification.

Post-implementation flow

operator EOA
 └─(1) SuperPaymaster: lock GToken → registerRole(ROLE_DVT)          [stake: single entry]
 └─(2) AAStarValidator.registerPublicKey(nodeId, pubkey) as operator
        → nodeOperator[nodeId]=operator
        → if requireStake: assert Registry.hasRole(ROLE_DVT,op) && lock≥minStake   [①②③]
 node co-signs UserOps  →  AAStarValidator.verifyAggregateSignature(nodeIds,…)
        → (optional) assert each nodeId's operator still active                     [liveness]
 misbehavior  →  DVTValidator: slash operator via nodeId→operator binding           [slashing]
 discovery    →  gossip roster {nodeId, apiEndpoint}; coordinator maps nodeId→operator to
                 check active/slashed state before including in a quorum

Open questions (for the challenge / finalization)

  1. Slashing linkage — how does DVTValidator resolve nodeId → operator? Event-relay
    vs on-chain view vs storing the binding in SuperPaymaster instead.
  2. Real-time liveness at verify — worth the per-verify gas, or off-chain pruning
    only (as DVTValidator already assumes)?
  3. Deployed-contract reconciliation — repo AAStarValidator.sol (permissionless
    source) vs deployed AAStarBLSAlgorithm v0.20.0 (onlyOwner): which is canonical,
    and does this change target a redeploy?
  4. roleId + minStake governance — confirm ROLE_DVT constant + who tunes minStake
    (Registry.configureRole, owner/governance).
  5. One operator, many nodes? — does an operator run multiple nodeIds under one stake,
    or one stake per nodeId? Affects the binding cardinality.

Cross-repo: AAStarCommunity/YetAnotherAA-Validator (AAStarValidator changes) +
AAStarCommunity/SuperPaymaster (interface confirm + slashing linkage). This issue is
filed to both. Related: YetAnotherAA-Validator#157 (N-of-M), #50 (hardening).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions