Embedded Agent

Topology

Choose the cohort that fits your trust model — single-agent for the simplest 2-of-2 wallet, multi-agent for redundancy and threshold flexibility.

Topology

The agent and threshold fields on the EmbeddedAgent constructor define the cohort: who holds shares, who must cooperate to sign, and what failure modes the wallet survives.

new EmbeddedAgent({
  agents: [
    { baseUrl: 'https://node-1.example', apiKey: '...' },
    { baseUrl: 'https://node-2.example', apiKey: '...' },
    // ... more if you want them
  ],
  threshold: 2,
  curve: Curve.Secp256k1,
});

Two rules govern the cohort:

  • Cohort size is always 1 + agent.length. The device sits at party 0; each entry in agent becomes a cohort party in array order (agent[0] = party 1, agent[1] = party 2, …).
  • Threshold is the signing quorum: how many of those parties must produce a partial signature to assemble a valid signature. Range is 2..=(1 + agent.length). The device is always one of the signers; the threshold says how many AGENTS must also sign.

Every agent[i].baseUrl must point at a distinct MPC node so cohort party indices stay unique (the constructor rejects duplicates after trailing-slash normalization).


Single-agent: 2-of-2 (the default)

The minimum embedded-wallet shape. Device + one cloud agent; both must sign every transaction.

new EmbeddedAgent({
  agents: [{ baseUrl: 'https://primary.example', apiKey: '...' }],
  threshold: 2,
  curve: Curve.Secp256k1,
});

When to use it. Consumer wallets where the agent acts as a 2FA-style co-signer; hot keys that should never be unilaterally usable from the device; the smallest possible MPC surface for prototypes.

What you give up. No survivability — losing either share ends the wallet (unless you wrap it in the sealed-bundle recovery path).


Multi-agent: redundancy via more cloud parties

Adding agents to the array adds cohort parties. With threshold 2, any of the agents can substitute for any other when signing — the device picks the first reachable agent. With threshold equal to the cohort size, every party must sign every transaction (maximum security, zero redundancy).

// 2-of-3: device + any one of two agents signs together.
// Tolerates one agent unreachable; quorum stays at 2.
new EmbeddedAgent({
  agents: [
    { baseUrl: 'https://primary.example',  apiKey: '...' },
    { baseUrl: 'https://recovery.example', apiKey: '...' },
  ],
  threshold: 2,
  curve: Curve.Secp256k1,
});

// 3-of-3: every party must sign. No agent can go offline mid-signature.
new EmbeddedAgent({
  agents: [
    { baseUrl: 'https://node-a.example', apiKey: '...' },
    { baseUrl: 'https://node-b.example', apiKey: '...' },
  ],
  threshold: 3,
  curve: Curve.Secp256k1,
});

// 2-of-4: device + any one of three agents. Tolerates two agents
// down simultaneously; useful for cross-region operator setups.
new EmbeddedAgent({
  agents: [
    { baseUrl: 'https://us-east.example', apiKey: '...' },
    { baseUrl: 'https://eu-west.example', apiKey: '...' },
    { baseUrl: 'https://ap-south.example', apiKey: '...' },
  ],
  threshold: 2,
  curve: Curve.Secp256k1,
});

Multi-agent picks the participating subset by array order

At signing time the SDK uses the device plus the first threshold - 1 agents in the array. So agent[0] is the "primary" the device routes to first; the other entries are backups that get used when you reshape the cohort by re-ordering the array on a future EmbeddedAgent construction.

The cohort math is fixed at create time — the agent array passed to the constructor is the cohort the DKG ran against. Reshuffling the array later is fine for choosing WHICH agents sign() reaches for, but you can't drop agents from the cohort or add new ones without resharing.


Picking a threshold

ThresholdCohortLiveness (agents that can be offline)Compromise budget (agents an attacker must take to forge)
2device + 1 agent01
2device + 2 agents11
2device + 3 agents21
3device + 2 agents02
3device + 4 agents22
4device + 4 agents13

Larger thresholds raise the compromise bar at the cost of liveness — every additional required signer is another network round-trip that must succeed for sign() to return. Most embedded-wallet integrations sit at threshold 2 across a 2-or-3-agent cohort.


Choosing between EmbeddedAgent and the lower-level surface

If your topology is "one device + Zafeguard agents over HTTPS," EmbeddedAgent is the right facade. If you need something the facade doesn't model — custom transports between cohort parties, exotic share layouts, hardware-key integrations — the ClusterAgent client is the escape hatch. It's the lower-level API exposed by the same package; reach for it only when the facade can't represent your setup.


Next

  • Quick start → — drop-in code for a single-agent 2-of-2 signer.
  • Presignature pool → — pre-mint presignatures so each sign() runs a single cohort round-trip instead of two.
  • Recovery → — share rotation, sealed-bundle backup, cold-recovery flows.

On this page