Skip to main content

Plan-Sign-Execute

Every operation that moves funds (earn, withdraw, transfer) follows a three-step flow. This keeps Legend non-custodial — your users’ keys never touch our servers.

The three steps

1. Plan

Your server tells Legend what you want to do:
POST /accounts/acc_xxx/plan/earn
{
  "amount": "1000000",
  "asset": "USDC",
  "network": "base",
  "protocol": "compound"
}
Legend generates the exact on-chain transaction, computes the EIP-712 typed data, and returns a plan containing:
  • plan_id — A temporary identifier (valid for 2 minutes)
  • details — The full transaction details, including any bridge steps
  • details.eip712_data.digest — The hash that needs to be signed
No on-chain state changes at this point. The plan is purely a preview.

2. Sign

The account’s signer (an EOA private key or Turnkey-managed key) signs the EIP-712 digest. This proves the key holder authorizes the transaction. The signing happens entirely on your side — Legend never sees the private key.

3. Execute

Your server sends the signature back to Legend:
POST /accounts/acc_xxx/plan/execute
{
  "plan_id": "pln_xxx",
  "signature": "0x..."
}
Legend verifies the signature, then submits the on-chain transaction. You get back status: "executing" and can monitor progress via the activities or events endpoints.

Why this pattern?

Non-custodial security. Legend constructs transactions but can never submit them without signer approval. Even if an attacker compromised a query key, they couldn’t move funds — they’d also need the signer key. Transparency. The plan step lets you (or your user) inspect exactly what will happen before committing. The EIP-712 typed data is a standardized, human-readable description of the transaction. Flexibility. The signer can be an EOA private key or a Turnkey-managed P256 key, controlled by either you or your end-user at your discretion. See Signer types.

EIP-712 signing

EIP-712 is an Ethereum standard for typed structured data signing. It produces signatures that are:
  • Bound to a specific contract — Can’t be replayed on a different contract
  • Bound to a specific chain — Can’t be replayed on a different network
  • Human-readable — Wallets can display what you’re signing
When you create a plan, the details.eip712_data contains:
FieldDescription
digestThe final hash to sign (this is what you pass to your signer)
domain_separatorIdentifies the contract and chain
hash_structHash of the structured transaction data

Plan expiration

Plans expire after 2 minutes. This prevents stale transactions from being executed when market conditions or balances have changed. If a plan expires, simply create a new one.

Diagram