← Back to profile

Anyenk · ● Live in production

Non-custodial multisig smart-account wallet

A wallet for companies where no single party can move funds. A quorum of the customer's own signers has to agree, plus one of two independent custody keys — and that rule is not a promise made by a backend, it is enforced on-chain by a weighted validator on an ERC-4337 smart account.

  • Solidity / EVM
  • ERC-4337 account abstraction
  • ZeroDev Kernel
  • Weighted validator
  • EIP-712
  • AWS KMS
  • Privy embedded wallets
  • TypeScript microservices
  • Kafka

01Three keys, one rule

Customer

Signer quorum

N of M or N of N, chosen by the customer

Anyenk

Operational key

AWS KMS · co-signs automatically

Third party

Backup key

Neutral custodian · recovery only

Smart account · weighted validator

quorum + (operational ∨ backup)  or  operational + backup

The customer

Customer signers

A set of people chosen by the customer, configured as N of M (any N of them) or N of N (all of them). Each one approves from an embedded wallet inside the app.

Anyenk · AWS KMS

Operational key

Lives in AWS KMS, never leaves it. Co-signs automatically once the customer quorum is reached, and is weighted so it can never move funds on its own.

Neutral third party

Backup key

Held by an independent custodian. Never used in the normal flow — it exists only for recovery, together with the operational key.

The rule

A set of signatures moves funds if and only if:

(customer quorum ∧ (A ∨ B)) ∨ (A ∧ B)

A = operational key · B = backup key

Who signsMoves funds?
Customer quorum alone — even every signer together✗ No
Operational key alone✗ No
Fewer signers than the quorum + operational key✗ No
Customer quorum + operational key✓ Yesnormal flow
Customer quorum + backup key✓ Yesout of band
Operational key + backup key✓ Yesrecovery

02Two layers: governance and cryptography

Both layers have “weights” and a “threshold”, but they mean different things and live in different services. Keeping them apart is what makes the system easy to reason about.

Layer 1 · Org service

App signature policy

Governance: how many people must approve. Stored as a threshold Θ = N and one weight of 1 per signer, so “collected weight ≥ threshold” literally reads “N distinct people approved”.

Layer 2 · Crypto service

On-chain weighted validator

Cryptography: which key signatures actually move funds. The policy is mapped into the validator of the smart account — customer signers keep their weight, and both custody keys get a derived weight W against an on-chain threshold T.

03The on-chain math

Given the app threshold Θ and the sum Σw of the customer signers' weights, one function derives the whole validator configuration:

T = max(2Θ, Σw + 1)   // on-chain threshold
W = T − Θ            // weight of each custody key

Five constraints hold for arbitrary weights. The Σw + 1 floor guarantees customers can never reach the threshold without a custody key; the 2Θ term is the only reason recovery works.

RequirementAlgebraHolds because
R1All customer signers together do not authorizeΣw < TT ≥ Σw + 1
R2Quorum + one custody key doesΘ + W ≥ TΘ + (T − Θ) = T
R3Both custody keys together do (recovery)2W ≥ TT ≥ 2Θ
R4One custody key alone does notW < TΘ ≥ 1
R5Sub-quorum + one custody key does not(Θ − 1) + W < T= T − 1

Worked example: “any 2 of 3”

Θ = 2 · weights [1, 1, 1] · Σw = 3
T = max(4, 4) = 4 · W = 2 → on-chain: A=2 B=2 s₁=1 s₂=1 s₃=1
SignaturesSum≥ 4Why
s₁1✗ Nono quorum
s₁ s₂2✗ Noquorum, but no custody key (R1)
s₁ s₂ s₃3✗ Noevery signer, still no custody key (R1)
s₁ + A3✗ Nosub-quorum + custody (R5)
s₁ s₂ + A4✓ Yesthe normal flow (R2)
A2✗ Nocustody key alone (R4)
A + B4✓ Yesrecovery (R3)

04Architecture

Two microservices split the two layers: org owns governance, and crypto owns everything that touches keys and the chain. They communicate through events.

Web app

Policy editor · approvals · Privy embedded wallets signing EIP-712

org service · Layer 1

  • Organizations, members, roles, Legal Owners
  • Account proposals & approvals
  • Signature policies (Θ, signer weights)
  • Applies completed policy changes
⇄ events (Kafka)

crypto service · Layer 2

  • Deploys smart accounts; maps policy → validator
  • Prepares UserOps on dedicated nonce lanes
  • Co-signs with the operational key in AWS KMS
  • Frames signatures and submits to the bundler

EVM chain

ERC-4337 bundler → ZeroDev Kernel smart account → weighted validator (threshold T)

Signing a transaction, step by step

  1. Step 1

    Prepare & freeze

    The crypto service prepares the UserOperation on its own nonce lane and freezes a snapshot: the exact operation and the policy in force. Editing the policy mid-way can never move the finish line the signers agreed to.

  2. Step 2

    Approve

    Each signer rebuilds the EIP-712 Approve message from the snapshot and signs it with their embedded wallet — typed data, never a personal_sign.

  3. Step 3

    Verify & record

    The backend checks, cheapest first: the caller is a signer in the snapshot, the hash matches, the signature recovers to their wallet and that wallet is an on-chain guardian. Collected weight is recomputed as a SUM of stored approvals, so concurrent signs are race-safe.

  4. Step 4

    Quorum reached

    When collected weight reaches the frozen threshold, the transaction is claimed atomically for submission — exactly once.

  5. Step 5

    Co-sign & submit

    The operational key signs inside AWS KMS. Customer signatures are framed with their guardian index, and the UserOperation goes to the bundler: on-chain, the weighted sum reaches T.

Anyenk's weight enters at the last step, not before: during collection the app only counts customer approvals against Θ; the on-chain sum is assembled once, at submit.

05How it's used at Anyenk today

Accounts born from governance

An organization proposes an account; its Legal Owner approves it. That approval creates the signature policy and the roles, and deploys the smart account with its signer set.

N of M, not weights

The policy editor asks for a set of signers and a single N — “Only one” or “N of M”. Nobody is asked to translate “any two of three” into weights and thresholds; the system derives them.

Policy changes are multisig too

Changing who can sign is itself a transaction that the current signers must approve. When it executes, the on-chain validator is renewed with the new configuration.

Cancel releases the account

A pending transaction or policy change can be cancelled by its creator, its approvers, the Legal Owner or an initiator. Cancelling voids every collected signature and frees the nonce lane.

Fiat payouts, same approvals

The same approval flow signs fiat payout intents as EIP-712 messages whose domain is bound to the account and environment, so a signature cannot be replayed across accounts or environments.

06Engineering safeguards

  • Exhaustive test: every threshold 1–8, 1–4 signers, weights 1–4, every coalition, with and without each custody key — 50,000+ cases must match the rule exactly.
  • One single function produces every validator configuration, for the first deploy and for every renew.
  • Roles are disjoint: a customer signer can never share an address with a custody key, and the two custody keys can never be the same.
  • Signature framing fails closed: an unrecoverable signature or unknown guardian is rejected, never guessed — a guess would burn the nonce on the wrong vote slot.
  • Thresholds are bound-checked against the validator's uint24 after the floor is applied, so they can never be silently truncated.
  • An independent second implementation audits every account's policy shape, read-only.