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
Signer quorum
N of M or N of N, chosen by the customer
Operational key
AWS KMS · co-signs automatically
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:
A = operational key · B = backup key
| Who signs | Moves 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:
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.
| Requirement | Algebra | Holds because | |
|---|---|---|---|
| R1 | All customer signers together do not authorize | Σw < T | T ≥ Σw + 1 |
| R2 | Quorum + one custody key does | Θ + W ≥ T | Θ + (T − Θ) = T |
| R3 | Both custody keys together do (recovery) | 2W ≥ T | T ≥ 2Θ |
| R4 | One custody key alone does not | W < T | Θ ≥ 1 |
| R5 | Sub-quorum + one custody key does not | (Θ − 1) + W < T | = T − 1 |
Worked example: “any 2 of 3”
| Signatures | Sum | ≥ 4 | Why |
|---|---|---|---|
| s₁ | 1 | ✗ No | no quorum |
| s₁ s₂ | 2 | ✗ No | quorum, but no custody key (R1) |
| s₁ s₂ s₃ | 3 | ✗ No | every signer, still no custody key (R1) |
| s₁ + A | 3 | ✗ No | sub-quorum + custody (R5) |
| s₁ s₂ + A | 4 | ✓ Yes | the normal flow (R2) |
| A | 2 | ✗ No | custody key alone (R4) |
| A + B | 4 | ✓ Yes | recovery (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
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
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.
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.
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.
Step 4
Quorum reached
When collected weight reaches the frozen threshold, the transaction is claimed atomically for submission — exactly once.
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.