|
| 1 | +# eip712 plugin |
| 2 | + |
| 3 | +Sign and verify EIP-712 structured typed data using ECDSA or Ed25519 keys managed by the CLI KMS. Stateless — no local state is written. Useful for permit flows, off-chain authorizations, meta-transactions, and dApp integrations on Hedera. |
| 4 | + |
| 5 | +Domain, types, and message each accept either an **inline JSON string** or a **path to a JSON file**. |
| 6 | + |
| 7 | +For sign/verify commands you can provide either: |
| 8 | + |
| 9 | +- **`--hash`** — a pre-computed EIP-712 digest (0x-prefixed keccak256 hex), OR |
| 10 | +- **`--domain` + `--types` + `--message`** — the full typed data (all three required together) |
| 11 | + |
| 12 | +These two input modes are mutually exclusive. |
| 13 | + |
| 14 | +--- |
| 15 | + |
| 16 | +### `hcli eip712 hash` |
| 17 | + |
| 18 | +Compute the EIP-712 digest (keccak256 hash) for a typed data payload without signing. |
| 19 | + |
| 20 | +| Option | Short | Type | Required | Description | |
| 21 | +| ----------- | ----- | ------ | -------- | -------------------------------------------------------------- | |
| 22 | +| `--domain` | `-d` | string | **yes** | EIP-712 domain as inline JSON or path to a JSON file | |
| 23 | +| `--types` | `-t` | string | **yes** | EIP-712 types definition as inline JSON or path to a JSON file | |
| 24 | +| `--message` | `-m` | string | **yes** | Message object as inline JSON or path to a JSON file | |
| 25 | + |
| 26 | +**Example:** |
| 27 | + |
| 28 | +``` |
| 29 | +hcli eip712 hash --domain '{"name":"MyApp","version":"1","chainId":295}' --types '{"Mail":[{"name":"from","type":"address"}]}' --message '{"from":"0xAb..."}' |
| 30 | +
|
| 31 | +hcli eip712 hash --domain ./domain.json --types ./types.json --message ./message.json |
| 32 | +``` |
| 33 | + |
| 34 | +**Output:** `{ hash }` |
| 35 | + |
| 36 | +- `hash` — EIP-712 digest (0x-prefixed keccak256) |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +### `hcli eip712 sign` |
| 41 | + |
| 42 | +Sign an EIP-712 typed data payload using a KMS-managed key. The algorithm (ECDSA or Ed25519) is **auto-detected from the key type** stored in the KMS. |
| 43 | + |
| 44 | +| Option | Short | Type | Required | Default | Description | |
| 45 | +| --------------- | ----- | ------ | -------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- | |
| 46 | +| `--key` | `-K` | string | no | operator | Signing key: `accountId:privateKey`, `ecdsa:private:{hex}`, `ed25519:private:{hex}`, key reference (`kr_xxx`), or alias | |
| 47 | +| `--key-manager` | `-k` | string | no | config default | Key manager: `local` or `local_encrypted` | |
| 48 | +| `--hash` | `-H` | string | no\* | — | Pre-computed EIP-712 digest (0x-prefixed hex). Mutually exclusive with typed data options | |
| 49 | +| `--domain` | `-d` | string | no\* | — | EIP-712 domain as inline JSON or path to a JSON file | |
| 50 | +| `--types` | `-t` | string | no\* | — | EIP-712 types definition as inline JSON or path to a JSON file | |
| 51 | +| `--message` | `-m` | string | no\* | — | Message object as inline JSON or path to a JSON file | |
| 52 | + |
| 53 | +\* Provide either `--hash` OR all three of `--domain`, `--types`, `--message`. |
| 54 | + |
| 55 | +**Example:** |
| 56 | + |
| 57 | +``` |
| 58 | +hcli eip712 sign --key my-ecdsa-key --domain ./domain.json --types ./types.json --message ./message.json |
| 59 | +
|
| 60 | +hcli eip712 sign --key my-ed25519-key --hash 0x<keccak256-hex> |
| 61 | +``` |
| 62 | + |
| 63 | +**Output (ECDSA key):** `{ signerEvm, signature, hash, r, s, v }` |
| 64 | + |
| 65 | +- `signerEvm` — EVM address of the signer (checksum format) |
| 66 | +- `signature` — combined 65-byte hex string (`0x` + r + s + v) |
| 67 | +- `hash` — EIP-712 digest that was signed (0x-prefixed keccak256) |
| 68 | +- `r`, `s` — 32-byte hex components |
| 69 | +- `v` — recovery id (27 or 28) |
| 70 | + |
| 71 | +**Output (Ed25519 key):** `{ signerPublicKey, hash, signature }` |
| 72 | + |
| 73 | +- `signerPublicKey` — Ed25519 public key of the signer (0x-prefixed hex) |
| 74 | +- `hash` — EIP-712 digest that was signed (0x-prefixed keccak256) |
| 75 | +- `signature` — 64-byte Ed25519 signature over the digest (0x-prefixed hex) |
| 76 | + |
| 77 | +--- |
| 78 | + |
| 79 | +### `hcli eip712 verify` |
| 80 | + |
| 81 | +Verify an EIP-712 signature. The algorithm is **auto-detected from the signature length**: |
| 82 | + |
| 83 | +- **65-byte signature** (0x + 130 hex chars) → ECDSA path: recovers the EVM signer address via `ecrecover`, optionally asserts it matches `--expected-signer` |
| 84 | +- **64-byte signature** (0x + 128 hex chars) → Ed25519 path: verifies the signature against a KMS-managed public key |
| 85 | + |
| 86 | +Passing `--key`/`--key-manager` with a 65-byte signature, or `--expected-signer` with a 64-byte signature, is a validation error. |
| 87 | + |
| 88 | +| Option | Short | Type | Required | Default | Description | |
| 89 | +| ------------------- | ----- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------ | |
| 90 | +| `--key` | `-K` | string | no | operator | Public key to verify against (Ed25519 only). Key reference, account alias, or account ID | |
| 91 | +| `--key-manager` | `-k` | string | no | config default | Key manager: `local` or `local_encrypted` (Ed25519 only) | |
| 92 | +| `--hash` | `-H` | string | no\* | — | Pre-computed EIP-712 digest (0x-prefixed hex). Mutually exclusive with typed data options | |
| 93 | +| `--domain` | `-d` | string | no\* | — | EIP-712 domain as inline JSON or path to a JSON file | |
| 94 | +| `--types` | `-t` | string | no\* | — | EIP-712 types definition as inline JSON or path to a JSON file | |
| 95 | +| `--message` | `-m` | string | no\* | — | Signed message object as inline JSON or path to a JSON file | |
| 96 | +| `--signature` | `-s` | string | **yes** | — | Signature to verify: 0x-prefixed 65-byte hex (ECDSA) or 64-byte hex (Ed25519) | |
| 97 | +| `--expected-signer` | `-e` | string | no | — | Assert recovered address matches (ECDSA only): EVM address (`0x...`), account ID, or alias | |
| 98 | + |
| 99 | +\* Provide either `--hash` OR all three of `--domain`, `--types`, `--message`. |
| 100 | + |
| 101 | +**Example:** |
| 102 | + |
| 103 | +``` |
| 104 | +# ECDSA — recover signer |
| 105 | +hcli eip712 verify --domain ./domain.json --types ./types.json --message ./message.json --signature 0x<65-byte-hex> |
| 106 | +
|
| 107 | +# ECDSA — assert expected signer |
| 108 | +hcli eip712 verify --hash 0x<keccak256> --signature 0x<65-byte-hex> --expected-signer 0xAbCd...1234 |
| 109 | +hcli eip712 verify --hash 0x<keccak256> --signature 0x<65-byte-hex> --expected-signer 0.0.12345 |
| 110 | +hcli eip712 verify --hash 0x<keccak256> --signature 0x<65-byte-hex> --expected-signer my-alias |
| 111 | +
|
| 112 | +# Ed25519 — verify against key |
| 113 | +hcli eip712 verify --key my-ed25519-key --domain ./domain.json --types ./types.json --message ./message.json --signature 0x<64-byte-hex> |
| 114 | +hcli eip712 verify --key my-ed25519-key --hash 0x<keccak256> --signature 0x<64-byte-hex> |
| 115 | +``` |
| 116 | + |
| 117 | +**Output (ECDSA):** `{ recoveredSigner, match? }` |
| 118 | + |
| 119 | +- `recoveredSigner` — EVM address recovered from the signature |
| 120 | +- `match` — boolean, only present when `--expected-signer` is provided |
| 121 | + |
| 122 | +**Output (Ed25519):** `{ signerPublicKey, hash, verified }` |
| 123 | + |
| 124 | +- `signerPublicKey` — Ed25519 public key used for verification (raw hex) |
| 125 | +- `hash` — EIP-712 digest that was verified (0x-prefixed keccak256) |
| 126 | +- `verified` — boolean, whether the signature is valid for the given key and message |
| 127 | + |
| 128 | +--- |
| 129 | + |
| 130 | +## Notes |
| 131 | + |
| 132 | +- `--primary-type` is not a CLI option. ethers.js infers the primary type from the types definition automatically. |
| 133 | +- The plugin is stateless — no entries are written to `~/.hiero-cli/state/`. |
| 134 | +- `sign` auto-detects the algorithm from the resolved key's type in the KMS. Passing an unsupported algorithm throws a `ValidationError`. |
| 135 | +- `verify` auto-detects the algorithm from the signature length. Mixing algorithm-specific options with the wrong signature length throws a `ValidationError`. |
0 commit comments