@haven_ai/signer 0.1.0-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -0
- package/dist/cli.cjs +637 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +635 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +614 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +591 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# @haven_ai/signer
|
|
2
|
+
|
|
3
|
+
The Haven **edge signer**. It holds the delegate key locally and signs — and
|
|
4
|
+
that's all it does. It pairs with the hosted, keyless `@haven_ai/mcp-server`:
|
|
5
|
+
the hosted server constructs and relays, this signs. The key never leaves this
|
|
6
|
+
process, and only signatures (and the standard x402 header) ever come out.
|
|
7
|
+
|
|
8
|
+
Design: [`docs/architecture/07-edge-signer.md`](../../docs/architecture/07-edge-signer.md).
|
|
9
|
+
Contract: [`docs/architecture/06-hosted-mcp-connect-flow.md`](../../docs/architecture/06-hosted-mcp-connect-flow.md).
|
|
10
|
+
|
|
11
|
+
## Two ways to use it
|
|
12
|
+
|
|
13
|
+
**As a local MCP signer** (for Claude Desktop / Code / Cursor) — run it
|
|
14
|
+
alongside the hosted Haven connection:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
HAVEN_DELEGATE_KEY=0x... npx @haven_ai/signer
|
|
18
|
+
# or
|
|
19
|
+
npx @haven_ai/signer --credentials /path/to/haven-agent.json
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
On first launch, the signer prints the delegate address, any wallet/network
|
|
23
|
+
metadata found in the credential file, and the sign-only tool list. It refuses
|
|
24
|
+
to start until acknowledged with either `HAVEN_SIGNER_ACK=<hash>` or
|
|
25
|
+
`npx @haven_ai/signer --credentials /path/to/haven-agent.json --ack`.
|
|
26
|
+
|
|
27
|
+
It exposes two stdio MCP tools:
|
|
28
|
+
|
|
29
|
+
| Tool | Does | Emits |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `haven_sign` | Sign the `payload_hash` from `haven_pay` / `haven_x402_authorize`; for x402, record `x402.expected` and return a binding | `{ signature }` or `{ signature, x402_binding }` |
|
|
32
|
+
| `haven_x402_sign_header` | Build + sign the EIP-3009 `X-PAYMENT` header only when `payment_required` matches the recorded `x402_binding` | `{ payment_header }` |
|
|
33
|
+
|
|
34
|
+
**As a library** (for SDK / autonomous agents):
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { createEdgeSigner } from '@haven_ai/signer'
|
|
38
|
+
|
|
39
|
+
const signer = createEdgeSigner(process.env.HAVEN_DELEGATE_KEY!)
|
|
40
|
+
const signature = signer.signPaymentHash(payloadHash)
|
|
41
|
+
const funding = signer.signX402FundingHash(payloadHash, {
|
|
42
|
+
resourceUrl,
|
|
43
|
+
merchantTo,
|
|
44
|
+
amount,
|
|
45
|
+
asset,
|
|
46
|
+
network,
|
|
47
|
+
auth,
|
|
48
|
+
})
|
|
49
|
+
const { paymentHeader } = await signer.buildX402PaymentHeader(paymentRequired, funding.x402Binding)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Orchestration
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
hosted: haven_pay -> { payment_id, payload_hash }
|
|
56
|
+
local: haven_sign -> { signature }
|
|
57
|
+
hosted: haven_submit -> { status, tx_hash }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
x402 (two delegate signatures, both local):
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
hosted: haven_x402_authorize -> { payment_id, payload_hash, x402.expected }
|
|
64
|
+
local: haven_sign + expected -> funding signature + x402_binding
|
|
65
|
+
hosted: haven_submit -> funds Safe -> delegate EOA
|
|
66
|
+
local: haven_x402_sign_header -> X-PAYMENT header only if binding matches
|
|
67
|
+
agent: retry merchant with X-PAYMENT
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
For x402, pass `x402.expected` from the hosted `haven_x402_authorize` response
|
|
71
|
+
unchanged into the local `haven_sign` call. The signer records that context and
|
|
72
|
+
returns a process-local `x402_binding`; pass that binding into
|
|
73
|
+
`haven_x402_sign_header` after `haven_submit` confirms. The signer refuses to
|
|
74
|
+
authorize the merchant header when the fresh merchant challenge has a different
|
|
75
|
+
amount, merchant recipient, resource URL, token asset, or network than the
|
|
76
|
+
recorded funding intent, and consumes the binding after one successful header.
|
|
77
|
+
The expected context must also carry Haven's `auth` signature; configure
|
|
78
|
+
`HAVEN_X402_BINDING_SIGNER` (or `x402_binding_signer` in the credential file) so
|
|
79
|
+
the signer can reject locally invented or tampered x402 contexts before signing
|
|
80
|
+
the funding hash.
|
|
81
|
+
|
|
82
|
+
## Custody
|
|
83
|
+
|
|
84
|
+
The delegate key is read from `HAVEN_DELEGATE_KEY` or a `--credentials` file's
|
|
85
|
+
`delegate_key` (with a permissive-file warning). It stays in this process. The
|
|
86
|
+
signer makes no network calls — it can't leak the key to Haven or anyone else.
|
|
87
|
+
It needs no `api_key`: identity lives with the hosted connection, not here.
|
|
88
|
+
|
|
89
|
+
Connect Agent 2 may create the signer credential file locally during setup. In
|
|
90
|
+
that flow Haven receives the public signing address, proof, API-key hash/prefix,
|
|
91
|
+
and install status only; the plaintext API key and delegate key stay in local
|
|
92
|
+
protected storage/runtime config.
|
|
93
|
+
|
|
94
|
+
## Local audit
|
|
95
|
+
|
|
96
|
+
Every MCP signing operation appends a JSONL row locally. File-backed runs write
|
|
97
|
+
next to the credential as `<credential>.signer-audit.jsonl`; env-only runs use
|
|
98
|
+
`~/.haven/signer-audit.jsonl`. Rows include timestamp, tool, payload hash, and
|
|
99
|
+
delegate address. They never include the delegate key, signature, or x402
|
|
100
|
+
payment header.
|
|
101
|
+
|
|
102
|
+
## Hot-wallet minimization
|
|
103
|
+
|
|
104
|
+
Standard x402 briefly funds the delegate EOA before the merchant settles the
|
|
105
|
+
EIP-3009 authorization. Keep delegate balances transient: use small/reset-bound
|
|
106
|
+
x402 allowances, retry the original merchant session only after funding
|
|
107
|
+
confirms, and reconcile or sweep stranded delegate balances when the merchant
|
|
108
|
+
retry fails or does not settle before authorization expiry.
|