> ## Documentation Index
> Fetch the complete documentation index at: https://docs.legend.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Plan-Sign-Execute

> How Legend's non-custodial transaction flow works

# 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:

```json theme={null}
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:

```json theme={null}
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](/introduction#signer-types).

## EIP-712 signing

[EIP-712](https://eips.ethereum.org/EIPS/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:

| Field              | Description                                                   |
| ------------------ | ------------------------------------------------------------- |
| `digest`           | The final hash to sign (this is what you pass to your signer) |
| `domain_separator` | Identifies the contract and chain                             |
| `hash_struct`      | Hash 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

```mermaid theme={null}
sequenceDiagram
    participant S as Your Server
    participant L as Legend
    participant B as Blockchain

    S->>L: POST /plan/earn
    L->>B: Read wallet state
    B-->>L: Current state
    L-->>S: { plan_id, digest }

    Note over S: Sign digest locally<br/>(key never leaves your infra)

    S->>L: POST /plan/execute { signature }
    L->>L: Verify signature
    L->>B: Submit transaction
    L-->>S: { status: executing }
    B-->>L: Confirmation

    S->>L: GET /activities
    L-->>S: { status: confirmed }
```
