EXTENDED DOCUMENTATION

AA Social Recovery / AA 社交恢复集成方案

This document defines the recommended integration between

text
neo-abstract-account
and Morpheus
text
NeoDID + Privacy Oracle
.

本文定义

text
neo-abstract-account
与 Morpheus
text
NeoDID + 隐私预言机
的标准集成方案。

Goal / 目标

Recover control of an Abstract Account with privacy-preserving social factors such as Twitter, GitHub, Google, Email, Binance, or OKX, without exposing raw Web2 identity data on-chain.

在不把 Web2 明文身份暴露到链上的前提下,允许用户通过 Twitter、GitHub、Google、Email、Binance、OKX 等社交或平台身份恢复 Abstract Account 控制权。

Use a dedicated AA custom verifier, for example

text
MorpheusSocialRecoveryVerifier
, instead of modifying the AA core contract.

推荐新增一个独立的 AA 自定义验证器,例如

text
MorpheusSocialRecoveryVerifier
,而不是直接改 AA 核心合约。

Why:

  • text
    neo-abstract-account
    already supports per-account custom verifiers through
    text
    setVerifierContract
    .
  • Recovery logic remains isolated from the main wallet execution engine.
  • NeoDID master nullifiers and action nullifiers map naturally to recovery factors and one-time recovery approvals.
  • Oracle, NeoDID, and AA can all share one callback-oriented request model.
  • AA integrations may publicly namespace a recovery identity as
    text
    did:morpheus:neo_n3:aa:<account-id>
    while still requiring a private NeoDID recovery ticket for actual authorization.

Component Roles / 组件职责

1. Morpheus Oracle

  • Receives on-chain requests through
    text
    MorpheusOracle.request(...)
  • Emits
    text
    OracleRequested
  • Relayer forwards the payload to the Phala worker
  • Always fulfills the request with success or failure callback

2. NeoDID Worker

  • Verifies confidential provider data inside the TEE
  • For
    text
    provider = "web3auth"
    , verifies the JWT signature against Web3Auth JWKS inside the TEE and derives the stable DID root from token claims
  • Derives:
    • text
      master_nullifier
    • text
      action_nullifier
  • Signs a recovery ticket bound to a specific AA recovery round

3. MorpheusSocialRecoveryVerifier

  • Stores allowed recovery factors as
    text
    master_nullifier
  • Stores used approvals as
    text
    action_nullifier
  • Verifies the Morpheus / NeoDID signature
  • Applies threshold and timelock
  • Switches recovery ownership to
    text
    newOwner

4. Abstract Account

  • Keeps using its existing
    text
    custom verifier
    interface:
    • text
      verifyExecution(accountId)
    • text
      verifyExecutionMetaTx(accountId, signerHashes)
    • text
      verifyAdmin(accountId)
    • text
      verifyAdminMetaTx(accountId, signerHashes)
  • Delegates recovery authorization to the recovery verifier

Canonical Request Types / 标准请求类型

These request types can now be routed through the Morpheus oracle request pipeline:

  • text
    neodid_bind
  • text
    neodid_action_ticket
  • text
    neodid_recovery_ticket

This means AA recovery no longer needs a side-channel worker call. The preferred production path is:

这意味着 AA 恢复不需要旁路调用 worker。生产环境推荐路径是:

  1. User contract or recovery coordinator calls
    text
    MorpheusOracle.request("neodid_recovery_ticket", payload, callbackContract, callbackMethod)
    .
  2. Morpheus relayer routes the request to
    text
    /neodid/recovery-ticket
    .
  3. TEE signs the recovery ticket.
  4. Callback stores or forwards the ticket to the AA recovery verifier flow.

Recovery Ticket Schema / 恢复票据结构

text
neodid_recovery_ticket
returns a signed result shaped like:

json
{
  "mode": "neodid_recovery_ticket",
  "network": "neo_n3",
  "aa_contract": "0x711c1899a3b7fa0e055ae0d17c9acfcd1bef6423",
  "verifier_contract": "0x1111111111111111111111111111111111111111",
  "account_address": "0x6d0656f6dd91469db1c90cc1e574380613f43738",
  "account_id": "aa-social-recovery-demo",
  "new_owner": "0x89b05cac00804648c666b47ecb1c57bc185821b7",
  "recovery_nonce": "7",
  "expires_at": "1735689600",
  "provider": "github",
  "action_id": "aa_recovery:neo_n3:0x017520f068fd602082fe5572596185e62a4ad991:aa-social-recovery-demo:0x89b05cac00804648c666b47ecb1c57bc185821b7:7",
  "master_nullifier": "0x...",
  "action_nullifier": "0x...",
  "digest": "0x...",
  "signature": "...",
  "public_key": "...",
  "signer_address": "...",
  "signer_script_hash": "...",
  "output_hash": "...",
  "attestation_hash": "...",
  "verification": {
    "output_hash": "...",
    "attestation_hash": "...",
    "signature": "...",
    "public_key": "...",
    "tee_attestation": {
      "app_id": "...",
      "compose_hash": "...",
      "report_data": "0x..."
    }
  }
}

What The Verifier Must Check / 验证器必须检查的内容

The AA recovery verifier should verify:

  • text
    signature
    is valid for
    text
    digest
  • signer public key matches the configured NeoDID/Morpheus verifier key
  • text
    expires_at
    has not passed
  • text
    aa_contract
    matches the configured AA master contract
  • text
    account_id
    matches the account being recovered
  • text
    new_owner
    matches the pending recovery target
  • text
    recovery_nonce
    matches the current recovery round
  • text
    master_nullifier
    belongs to an allowed recovery factor
  • text
    action_nullifier
    has not already been used

AA 恢复验证器应验证:

  • text
    signature
    text
    digest
    有效
  • 签名公钥等于预配置的 NeoDID/Morpheus verifier key
  • text
    expires_at
    未过期
  • text
    aa_contract
    与当前 AA 主合约一致
  • text
    account_id
    与被恢复账户一致
  • text
    new_owner
    与本次待恢复的新地址一致
  • text
    recovery_nonce
    与当前恢复轮次一致
  • text
    master_nullifier
    属于允许的恢复因子集合
  • text
    action_nullifier
    未被使用

Confidential Input Model / 隐私输入模型

Sensitive fields should be encrypted with the Morpheus Oracle public key and passed as

text
encrypted_params
. If the ciphertext is too large for the chain request payload, store it first and pass
text
encrypted_params_ref
instead.

敏感字段应使用 Morpheus Oracle 公钥加密,并通过

text
encrypted_params
传入。

Example confidential patch:

json
{
  "id_token": "<web3auth jwt>",
  "verified_email": "alice@example.com",
  "linked_accounts": ["google", "email", "sms"]
}

Example on-chain request payload:

json
{
  "provider": "web3auth",
  "network": "neo_n3",
  "aa_contract": "0x711c1899a3b7fa0e055ae0d17c9acfcd1bef6423",
  "verifier_contract": "0x1111111111111111111111111111111111111111",
  "account_id": "aa-social-recovery-demo",
  "new_owner": "0x89b05cac00804648c666b47ecb1c57bc185821b7",
  "recovery_nonce": "7",
  "expires_at": "1735689600",
  "encrypted_params": "<base64 ciphertext>"
}

Large-JWT alternative:

json
{
  "provider": "web3auth",
  "network": "neo_n3",
  "aa_contract": "0x711c1899a3b7fa0e055ae0d17c9acfcd1bef6423",
  "verifier_contract": "0x1111111111111111111111111111111111111111",
  "account_id": "aa-social-recovery-demo",
  "new_owner": "0x89b05cac00804648c666b47ecb1c57bc185821b7",
  "recovery_nonce": "7",
  "expires_at": "1735689600",
  "encrypted_params_ref": "<secret_ref>"
}

Web3Auth As The DID Root / 用 Web3Auth 作为 DID 根身份

Recommended production model:

  • users authenticate with Web3Auth
  • multiple linked social providers still map to one stable Web3Auth user id
  • NeoDID uses:
    • text
      provider = "web3auth"
    • text
      id_token = <Web3Auth JWT>
  • the TEE verifies the JWT and derives the stable provider root internally
  • text
    provider_uid
    , if sent at all, is only treated as an optional consistency check
  • AA recovery verifiers only care about NeoDID tickets derived from that stable identifier

推荐生产模式:

  • 用户先通过 Web3Auth 登录
  • 多个社交账号在 Web3Auth 内部聚合成同一个稳定用户 id
  • NeoDID 统一使用:
    • text
      provider = "web3auth"
    • text
      id_token = <Web3Auth JWT>
  • TEE 在内部验证 JWT,并派生稳定的 provider 根标识
  • 如果额外传入
    text
    provider_uid
    ,它只作为可选一致性检查使用
  • AA 恢复验证器只消费由这个稳定标识导出的 NeoDID 票据,不关心底层具体用了 Google、Email 还是 SMS

Setup Phase / 初始化阶段

  1. User binds Web2 / exchange identities into NeoDID.
  2. User registers selected
    text
    master_nullifier
    values into
    text
    MorpheusSocialRecoveryVerifier
    .
  3. User sets:
    • threshold, for example
      text
      2-of-3
    • timelock, for example
      text
      3 days
    • recovery nonce start value

Recovery Phase / 恢复阶段

  1. User loses access to the original owner wallet.
  2. User chooses a new owner address
    text
    newOwner
    .
  3. User requests one or more
    text
    neodid_recovery_ticket
    approvals through Morpheus Oracle.
  4. Each successful factor submits one ticket to the verifier.
  5. The verifier marks each
    text
    action_nullifier
    as used and counts unique approved
    text
    master_nullifier
    factors.
  6. Once threshold is reached, the verifier opens a pending recovery timelock.
  7. When timelock expires, the verifier finalizes the recovery and switches the verifier-side owner to
    text
    newOwner
    .
  8. The recovered owner rotates AA admins/managers immediately.

Why This Is Better Than Dome-Only Recovery / 为什么优于仅 Dome 恢复

AA already has a dome + oracle inactivity path, but that path is best for inactivity unlocking, not for multi-factor identity recovery.

AA 现在已有 dome + oracle 的不活跃恢复通道,但那条路径更适合“不活跃后解锁”,不适合表达多因子身份恢复。

This NeoDID-based model adds:

  • privacy-preserving factor commitments
  • one-time recovery approvals via
    text
    action_nullifier
  • factor reuse prevention
  • multi-provider thresholds
  • recovery-round binding through
    text
    recovery_nonce
  • portable TEE attestation and signature evidence

Security Rules / 安全规则

Do not ship this flow without:

  • at least
    text
    2-of-N
    threshold for valuable accounts
  • text
    expires_at
  • text
    recovery_nonce
  • timelock
  • text
    cancelRecovery
  • text
    usedActionNullifier
  • post-recovery admin rotation

高价值账户不应使用单因子恢复。至少要有:

  • text
    2-of-N
    阈值
  • text
    expires_at
  • text
    recovery_nonce
  • timelock
  • text
    cancelRecovery
  • text
    usedActionNullifier
  • 恢复完成后的管理员轮换

Suggested verifier-side interface:

csharp
public static void SetupRecovery(
    ByteString accountId,
    UInt160 aaContract,
    ByteString[] allowedMasterNullifiers,
    BigInteger threshold,
    BigInteger timelockSeconds);

public static void SubmitRecoveryTicket(
    ByteString accountId,
    UInt160 newOwner,
    BigInteger recoveryNonce,
    ByteString masterNullifier,
    ByteString actionNullifier,
    string expiresAt,
    ByteString verificationSignature);

public static void FinalizeRecovery(ByteString accountId);
public static void CancelRecovery(ByteString accountId);

Integration Status In This Repo / 当前仓库里的实现状态

Implemented here:

  • worker route:
    text
    /neodid/recovery-ticket
  • web proxy route:
    text
    /api/neodid/recovery-ticket
  • relayer routing support for
    text
    neodid_recovery_ticket
  • on-chain callback envelope preservation for recovery ticket fields

Still belongs to the AA repository:

  • concrete
    text
    MorpheusSocialRecoveryVerifier
    contract
  • verifier deployment and live AA integration tests
  • frontend recovery wizard inside
    text
    neo-abstract-account
CURRENT DESIGNUPDATED FOR DUAL-CVM ARCHITECTURE
Morpheus Oracle