@agenttrust-sdk/mcp 0.2.1 → 0.2.3

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.
Files changed (55) hide show
  1. package/dist/embedded-data/devnet-attestor-trace.json +32 -0
  2. package/dist/embedded-data/devnet-chained-validation.json +52 -0
  3. package/dist/embedded-data/devnet-counterparties.json +53 -0
  4. package/dist/embedded-data/devnet-demo-policies.json +46 -0
  5. package/dist/embedded-data/devnet-namespaces.json +107 -0
  6. package/dist/embedded-data/devnet-smoke.json +24 -0
  7. package/dist/embedded-docs/getting-started/architecture-overview.mdx +85 -0
  8. package/dist/embedded-docs/getting-started/quickstart.mdx +100 -0
  9. package/dist/embedded-docs/index.mdx +64 -0
  10. package/dist/embedded-docs/integration-guides/capability-namespaces.mdx +15 -0
  11. package/dist/embedded-docs/integration-guides/custom-attestor.mdx +15 -0
  12. package/dist/embedded-docs/integration-guides/facilitator-adapters.mdx +85 -0
  13. package/dist/embedded-docs/integration-guides/pay-sh-adapter.mdx +110 -0
  14. package/dist/embedded-docs/integration-guides/x402-facilitator.mdx +79 -0
  15. package/dist/embedded-docs/programs/policy-vault/counterparty-tier-policy.mdx +15 -0
  16. package/dist/embedded-docs/programs/policy-vault/index.mdx +68 -0
  17. package/dist/embedded-docs/programs/policy-vault/kill-switch-policy.mdx +15 -0
  18. package/dist/embedded-docs/programs/policy-vault/require-validation-policy.mdx +15 -0
  19. package/dist/embedded-docs/programs/policy-vault/spending-policy.mdx +15 -0
  20. package/dist/embedded-docs/programs/policy-vault/velocity-policy.mdx +15 -0
  21. package/dist/embedded-docs/programs/trustgate.mdx +53 -0
  22. package/dist/embedded-docs/programs/validation-registry.mdx +49 -0
  23. package/dist/embedded-docs/reference/byte-offset-reference.mdx +20 -0
  24. package/dist/embedded-docs/reference/changelog.mdx +19 -0
  25. package/dist/embedded-docs/reference/devnet-program-ids.mdx +24 -0
  26. package/dist/embedded-docs/reference/discriminator-constants.mdx +16 -0
  27. package/dist/embedded-docs/reference/formal-verification.mdx +19 -0
  28. package/dist/embedded-docs/reference/mainnet-program-ids.mdx +16 -0
  29. package/dist/embedded-docs/reference/quantu-agent-registry.mdx +15 -0
  30. package/dist/embedded-docs/sdk/atomic-tx-invariant.mdx +37 -0
  31. package/dist/embedded-docs/sdk/gate-payment.mdx +22 -0
  32. package/dist/embedded-docs/sdk/index.mdx +73 -0
  33. package/dist/embedded-docs/sdk/mount-trustgate.mdx +15 -0
  34. package/dist/embedded-examples/attestor-demo/README.md +100 -0
  35. package/dist/embedded-examples/pay-sh-demo/README.md +136 -0
  36. package/dist/embedded-examples/pay-sh-demo/src/deps-real.ts +150 -0
  37. package/dist/embedded-examples/pay-sh-demo/src/deps.ts +150 -0
  38. package/dist/embedded-examples/pay-sh-demo/src/index.ts +471 -0
  39. package/dist/embedded-examples/pay-sh-demo/src/middleware.ts +198 -0
  40. package/dist/embedded-examples/pay-sh-demo/src/policy.ts +247 -0
  41. package/dist/embedded-examples/pay-sh-demo/src/x402.ts +140 -0
  42. package/dist/index.js +73 -18
  43. package/dist/index.js.map +1 -1
  44. package/dist/resources/docs.js +69 -46
  45. package/dist/resources/docs.js.map +1 -1
  46. package/dist/server.js +6 -1
  47. package/dist/server.js.map +1 -1
  48. package/dist/tools/discovery/docs.js +7 -0
  49. package/dist/tools/discovery/docs.js.map +1 -1
  50. package/dist/tools/discovery/facilitator-walkthrough.js +44 -18
  51. package/dist/tools/discovery/facilitator-walkthrough.js.map +1 -1
  52. package/dist/tools/read/demo-state.js +7 -4
  53. package/dist/tools/read/demo-state.js.map +1 -1
  54. package/dist/trustgate/server/src/facilitators/README.md +241 -0
  55. package/package.json +2 -2
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: Atomic-tx invariant
3
+ description: SDK and facilitator rules that keep policy checks tied to settlement.
4
+ ---
5
+
6
+ AgentTrust treats a policy check as useful only when the facilitator enforces the same payment context through settlement.
7
+
8
+ Production settlement must compose:
9
+
10
+ 1. `gate_payment`
11
+ 2. SPL transfer
12
+ 3. `emit_feedback`
13
+
14
+ All three succeed, or all three revert. That is the invariant that keeps a Pay.sh payment from settling without the AgentTrust feedback record, and keeps feedback from being emitted for a payment that never moved.
15
+
16
+ ## Adapter responsibilities
17
+
18
+ The adapter validates that the retry proof still matches the verify-time context:
19
+
20
+ | Check | Why it exists |
21
+ | --- | --- |
22
+ | `paymentIdHash` replay binding | prevents duplicate or raced settlement calls |
23
+ | amount, mint, recipient cross-check | prevents paying a different asset or recipient than the policy checked |
24
+ | facilitator fee payer != transfer authority | prevents self-pay feedback |
25
+ | SERVICE-signed challenge | prevents forged `paymentRequirements` racing a legitimate one |
26
+ | idempotent feedback lookup | makes retries return a stable receipt instead of double-emitting |
27
+
28
+ ## Demo vs production
29
+
30
+ `examples/pay-sh-demo` stubs `validateOnChainTx` and `emitFeedbackCpi` so the route can run in CI. Production fills those same dependency seams with RPC parsing and the Anchor feedback call.
31
+
32
+ | Source | Path |
33
+ | --- | --- |
34
+ | facilitator routes | [`trustgate/server/src/routes/settle.ts`](https://github.com/agenttrust-labs/agenttrust/blob/main/trustgate/server/src/routes/settle.ts) |
35
+ | Pay.sh proof validator | [`trustgate/server/src/facilitators/pay-sh/proof-validator.ts`](https://github.com/agenttrust-labs/agenttrust/blob/main/trustgate/server/src/facilitators/pay-sh/proof-validator.ts) |
36
+ | Pay.sh feedback helper | [`trustgate/server/src/facilitators/pay-sh/feedback.ts`](https://github.com/agenttrust-labs/agenttrust/blob/main/trustgate/server/src/facilitators/pay-sh/feedback.ts) |
37
+ | Pay.sh demo deps | [`examples/pay-sh-demo/src/deps.ts`](https://github.com/agenttrust-labs/agenttrust/blob/main/examples/pay-sh-demo/src/deps.ts) |
@@ -0,0 +1,22 @@
1
+ ---
2
+ title: gatePayment
3
+ description: Read-only policy decision call for facilitators.
4
+ ---
5
+
6
+ `In progress`
7
+
8
+ `gatePayment()` simulates PolicyVault and returns `Allow`, `Deny`, or `RequireValidation`. It remains useful when a service already owns its x402 routing layer and only wants the AgentTrust decision.
9
+
10
+ For Pay.sh, the adapter path wraps this lower-level decision in:
11
+
12
+ 1. x402 challenge parsing
13
+ 2. SERVICE signature verification
14
+ 3. proof validation
15
+ 4. feedback emission
16
+
17
+ | Source | Path |
18
+ | --- | --- |
19
+ | SDK client | [`trustgate/sdk/src/client.ts`](https://github.com/agenttrust-labs/agenttrust/blob/main/trustgate/sdk/src/client.ts) |
20
+ | Pay.sh adapter | [`trustgate/server/src/facilitators/pay-sh/index.ts`](https://github.com/agenttrust-labs/agenttrust/blob/main/trustgate/server/src/facilitators/pay-sh/index.ts) |
21
+ | shared types | [`trustgate/sdk/src/types.ts`](https://github.com/agenttrust-labs/agenttrust/blob/main/trustgate/sdk/src/types.ts) |
22
+ | package README | [`trustgate/sdk/README.md`](https://github.com/agenttrust-labs/agenttrust/blob/main/trustgate/sdk/README.md) |
@@ -0,0 +1,73 @@
1
+ ---
2
+ title: "@agenttrust-sdk/trustgate"
3
+ description: TypeScript client helpers, Express middleware, and atomicity guard.
4
+ ---
5
+
6
+ The SDK is the facilitator-facing TypeScript package. The server adapter layer currently carries the concrete Pay.sh integration and the demo path; the package API remains the smaller client / Express surface for apps that call AgentTrust directly.
7
+
8
+ ```bash
9
+ pnpm add @agenttrust-sdk/trustgate
10
+ ```
11
+
12
+ ## Imports
13
+
14
+ ```ts
15
+ import { mountTrustGate } from "@agenttrust-sdk/trustgate/express";
16
+ import { gatePayment, settle, dispute } from "@agenttrust-sdk/trustgate/client";
17
+ import {
18
+ AtomicityNotEnforcedError,
19
+ DEFAULT_DEVNET_PROGRAM_IDS,
20
+ derivePolicyPda,
21
+ } from "@agenttrust-sdk/trustgate";
22
+ ```
23
+
24
+ ## gatePayment
25
+
26
+ `gatePayment()` is a read-only decision call.
27
+
28
+ ```ts
29
+ type GateDecision =
30
+ | { kind: "Allow" }
31
+ | { kind: "Deny"; reasonCode: number; reasonName: string }
32
+ | { kind: "RequireValidation"; capabilityHash: number[] };
33
+ ```
34
+
35
+ The helper simulates the Anchor instruction and parses the return-data channel into the TypeScript union.
36
+
37
+ ## mountTrustGate
38
+
39
+ `mountTrustGate(app, config)` adds x402 routes to an Express service in fewer than 50 lines.
40
+
41
+ ```ts
42
+ await mountTrustGate(app, {
43
+ rpcUrl: "https://api.devnet.solana.com",
44
+ facilitatorKeypair,
45
+ defaultPolicyId: 1,
46
+ network: "solana-devnet",
47
+ atomicityEnforced: true,
48
+ });
49
+ ```
50
+
51
+ ## Atomicity guard
52
+
53
+ `settle`, `dispute`, and middleware config require:
54
+
55
+ ```ts
56
+ { atomicityEnforced: true }
57
+ ```
58
+
59
+ The marker is literal `true`, not `boolean`, and the runtime guard throws if a caller bypasses TypeScript with a cast. The server adapter path extends this into proof validation and feedback emission.
60
+
61
+ ## Current surface
62
+
63
+ | API | Status |
64
+ | --- | --- |
65
+ | `gatePayment` | implemented |
66
+ | `mountTrustGate` `/verify` | implemented |
67
+ | `mountTrustGate` `/receipt` | implemented |
68
+ | Pay.sh adapter | implemented in `@agenttrust/trustgate-server` workspace package |
69
+ | Pay.sh demo | implemented in `examples/pay-sh-demo` |
70
+ | `settle` | guarded SDK surface; server adapter validation path is active |
71
+ | `dispute` | guarded SDK surface; negative feedback route remains narrower |
72
+
73
+ Source: `trustgate/sdk/src`.
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: mountTrustGate
3
+ description: Express middleware that mounts AgentTrust x402 routes.
4
+ ---
5
+
6
+ `In progress`
7
+
8
+ `mountTrustGate(app, config)` adds `/verify`, `/receipt`, `/settle`, and `/dispute` handlers to an Express service. The SDK enforces the atomicity config before binding routes.
9
+
10
+ | Source | Path |
11
+ | --- | --- |
12
+ | Express middleware | [`trustgate/sdk/src/express.ts`](https://github.com/agenttrust-labs/agenttrust/blob/main/trustgate/sdk/src/express.ts) |
13
+ | x402 helpers | [`trustgate/sdk/src/x402.ts`](https://github.com/agenttrust-labs/agenttrust/blob/main/trustgate/sdk/src/x402.ts) |
14
+ | atomicity tests | [`trustgate/sdk/test/atomicity.test.ts`](https://github.com/agenttrust-labs/agenttrust/blob/main/trustgate/sdk/test/atomicity.test.ts) |
15
+
@@ -0,0 +1,100 @@
1
+ # attestor-demo
2
+
3
+ Devnet ValidationRegistry attestor-lifecycle demo. Captures a real on-chain
4
+ trace through all 5 ValidationRegistry instructions, proving the third leg
5
+ of the ERC-8004 trust stack works end-to-end against the deployed devnet
6
+ program at [`Cx4RFa6ysw3qXYhugPkF8pFSWBkmKq59h2dWgF2tKhtv`](https://explorer.solana.com/address/Cx4RFa6ysw3qXYhugPkF8pFSWBkmKq59h2dWgF2tKhtv?cluster=devnet).
7
+
8
+ ```bash
9
+ pnpm install
10
+ pnpm --filter ./examples/attestor-demo run smoke
11
+ ```
12
+
13
+ ## Live devnet trace (2026-05-06)
14
+
15
+ > **AgentTrust ValidationRegistry — full lifecycle, live on Solana devnet.**
16
+
17
+ Subject (Quantu agent_account): [`5PfaofvEUf3adtJwMho7zzbfvgxwxbvp2V5moqhtLK8y`](https://explorer.solana.com/address/5PfaofvEUf3adtJwMho7zzbfvgxwxbvp2V5moqhtLK8y?cluster=devnet)
18
+ Capability: `usdc-payment-policy.v1`
19
+
20
+ | step | tx | PDA |
21
+ |---|---|---|
22
+ | **register_namespace** | [`5B3PfDGYhzhusJwj…`](https://explorer.solana.com/tx/5B3PfDGYhzhusJwjXURnhpkZ2umipdegfNREtJbcgZySR7nr976CcSJXqYSzB8eSYT14W3yrzGuks75S7pdZD3WK?cluster=devnet) | [`34gonn86FjxzXZMGd43RSvQVyH1r6PrGV9xnHXjjkEwR`](https://explorer.solana.com/address/34gonn86FjxzXZMGd43RSvQVyH1r6PrGV9xnHXjjkEwR?cluster=devnet) |
23
+ | **register_attestor** | [`Ct3SQ4CR9bu6oijR…`](https://explorer.solana.com/tx/Ct3SQ4CR9bu6oijRELe7pnjj8KfMRVDiQ3AkytNQtYfF2yZBsThMJNoCDADnwWp37PYcsFJSEkBjXmaLY9a9eQD?cluster=devnet) | [`GTzWJzV5htNi1Ntqwq2e2ydu9h4rArnKQwzv2sJjC9zP`](https://explorer.solana.com/address/GTzWJzV5htNi1Ntqwq2e2ydu9h4rArnKQwzv2sJjC9zP?cluster=devnet) |
24
+ | **request_validation** | [`qBQzSTCWfkE9Xw1E…`](https://explorer.solana.com/tx/qBQzSTCWfkE9Xw1EZ2qRwo3Hv451cbVaTRKSa32KHpnL7sfCSVBEhjGinm5qod6W6LtCgAj7xvbhydHf1wjoKq9?cluster=devnet) | [`GnbrSzWsDw1rehCrFJ4ckiM9JJJeAHdjfNDt7QQy7vhV`](https://explorer.solana.com/address/GnbrSzWsDw1rehCrFJ4ckiM9JJJeAHdjfNDt7QQy7vhV?cluster=devnet) |
25
+ | **respond_to_validation** | [`CCxKvvQ9ZdboukcX…`](https://explorer.solana.com/tx/CCxKvvQ9ZdboukcXPp9jj1a3o53grGR9VjZux7kS1AAWqaVnRXVqhJjphsM1QYjny5oaVP4oRGThBLUQ41DyzwC?cluster=devnet) | [`C6Yr7oKcZ6sDVibR35SWbFnGCXyfQjLeRCiPbjxYq6vY`](https://explorer.solana.com/address/C6Yr7oKcZ6sDVibR35SWbFnGCXyfQjLeRCiPbjxYq6vY?cluster=devnet) |
26
+ | **revoke_validation** | (gated on REVOKE=1) | (in-place — sets revoked=true on the attestation PDA above) |
27
+
28
+ The `ValidationAttestation` PDA at row 4 is the on-chain artifact the
29
+ PolicyVault's `RequireValidation` policy reads via the byte-offset
30
+ parser at `programs/policy-vault/src/ext/validation_registry.rs`. Once
31
+ this PDA exists for `(subject, capability, attestor) = (5PfaofvE…,
32
+ sha256(usdc-payment-policy.v1), GTzWJzV5…)`, a subsequent
33
+ `gate_payment` call that passes this attestation account through the
34
+ `validation_attestation` slot turns a `RequireValidation` decision
35
+ into `Allow`.
36
+
37
+ Full machine-readable trace at [`devnet-attestor-trace.json`](./devnet-attestor-trace.json).
38
+
39
+ ## What this demonstrates
40
+
41
+ 1. **All 5 ValidationRegistry instructions reachable from the SDK**
42
+ (`@agenttrust-sdk/trustgate`'s `validation-registry` module exposes
43
+ PDA derivers + ix builders for every on-chain entry point).
44
+ 2. **The third leg of ERC-8004** is real on Solana — Quantu's
45
+ IdentityRegistry + ReputationRegistry sit at the foundation;
46
+ ValidationRegistry's capability attestation closes the trust stack.
47
+ 3. **The complete `RequireValidation` round-trip**: policy emits
48
+ capabilityHash → attestor responds → policy now Allows. Each step is
49
+ a separate on-chain tx; AgentTrust composes the PDAs without
50
+ trusting any off-chain coordination.
51
+
52
+ ## How it fits the demo narrative
53
+
54
+ The Pay.sh adapter (in `trustgate/server/src/facilitators/pay-sh/`)
55
+ already surfaces `capabilityHash` in its `formatChallenge` response when
56
+ the policy gate returns `RequireValidation`. A SERVICE that hits this
57
+ branch:
58
+
59
+ 1. Sees `decision.kind = "RequireValidation"` + `capabilityHash` in the
60
+ x402 `/verify` response body.
61
+ 2. Looks up the attestor service that handles that capability (typically
62
+ discovered out-of-band via a registry or hard-coded contract).
63
+ 3. Submits the claim payload off chain; the attestor responds on chain
64
+ via `respond_to_validation` (the script in this directory does this).
65
+ 4. Re-submits the payment to the SERVICE; the new `/verify` call
66
+ includes the `validation_attestation` PDA in the gate_payment
67
+ account list, the policy reads it, and the decision flips to
68
+ `Allow`.
69
+
70
+ The script proves steps 3-4 work end-to-end on devnet. Steps 1-2 are
71
+ business logic the SERVICE owns.
72
+
73
+ ## Configuration
74
+
75
+ | env var | default | meaning |
76
+ |--|--|--|
77
+ | `RPC_URL` | `https://api.devnet.solana.com` | Solana RPC endpoint |
78
+ | `KEYPAIR` | `~/.config/solana/id.json` | Facilitator keypair path |
79
+ | `REVOKE` | (unset) | When `1`, runs the optional 5th step (revoke_validation) |
80
+
81
+ ## Cost
82
+
83
+ ~0.012 SOL across all 5 steps (rent for namespace + attestor +
84
+ request + attestation PDAs, ~0.0023 SOL each, plus tx fees).
85
+
86
+ ## Idempotency
87
+
88
+ Re-running reuses:
89
+ - `examples/attestor-demo/attestor-keypair.json` (kept across runs so
90
+ the AttestorProfile PDA stays stable)
91
+ - The namespace PDA (skipped if `fetchCapabilityNamespace` already
92
+ returns a record)
93
+
94
+ It generates a fresh requester keypair each run so request_validation
95
+ doesn't collide on the `(subject, capability, requester)` PDA.
96
+
97
+ If you've already responded to a request once, the
98
+ `(subject, capability, attestor)` PDA exists and respond is skipped —
99
+ delete the attestor keypair file or change the `CAPABILITY_NAME` to
100
+ walk a fresh attestation lifecycle.
@@ -0,0 +1,136 @@
1
+ # pay-sh-demo
2
+
3
+ Pay.sh + AgentTrust TrustGate live-demo Express server. Single endpoint
4
+ (`/protected`), gated by a counterparty-tier policy and exercised end-to-end
5
+ through the AgentTrust facilitator pipeline.
6
+
7
+ ## Hit it now (no clone required)
8
+
9
+ The demo runs **live** at `demo.agenttrust.tech`. Hit `/protected` with
10
+ no payment proof and you'll get back a real x402 v2 challenge envelope:
11
+
12
+ ```bash
13
+ curl -i https://demo.agenttrust.tech/protected
14
+ ```
15
+
16
+ You'll see `HTTP/2 402` with a SERVICE-signed `payment-required` header
17
+ (base64 envelope). To walk the full Allow → settle → emit_feedback path,
18
+ clone the repo or use the `pay` CLI sandbox below.
19
+
20
+ ## Run locally
21
+
22
+ ```
23
+ pay --sandbox curl http://localhost:3402/protected
24
+ ```
25
+
26
+ ## Live devnet trace (2026-05-06)
27
+
28
+ > **AgentTrust + Pay.sh atomic settlement, live on Solana devnet.**
29
+
30
+ | step | tx |
31
+ |---|---|
32
+ | signed SPL transfer | [`5iV8EYmJh9XSXkBQrrbQ5L9kmBQabD3G3RXVPsHn9PkWceTFoeRsUV4g5aLLzZyRjeBoFvK3Woxr2cZa5xeUwhVD`](https://explorer.solana.com/tx/5iV8EYmJh9XSXkBQrrbQ5L9kmBQabD3G3RXVPsHn9PkWceTFoeRsUV4g5aLLzZyRjeBoFvK3Woxr2cZa5xeUwhVD?cluster=devnet) |
33
+ | emit_feedback CPI (PDA-signed → `agent_registry::give_feedback` → `atom_engine::update_stats`) | [`jMobmWJUAXuL8FmQujfxW9NmeMbzADUoABzqjiMeuc5m3YXyeuZeUw1ZJc29JGsqyWQGDY8q3vrtBdamhKXraag`](https://explorer.solana.com/tx/jMobmWJUAXuL8FmQujfxW9NmeMbzADUoABzqjiMeuc5m3YXyeuZeUw1ZJc29JGsqyWQGDY8q3vrtBdamhKXraag?cluster=devnet) |
34
+ | FeedbackEmissionLog PDA (init-only, score=100) | [`HB4BBi9jaD3VPcZkQQaH3DxukSqBiXfW8RejtaLa8bF3`](https://explorer.solana.com/address/HB4BBi9jaD3VPcZkQQaH3DxukSqBiXfW8RejtaLa8bF3?cluster=devnet) |
35
+
36
+ Captured in [`devnet-smoke.json`](./devnet-smoke.json). Reproduce with `scripts/devnet-smoke.ts`.
37
+
38
+ ## What it shows
39
+
40
+ The demo proves the full Pay.sh → AgentTrust loop without depending on a real
41
+ Solana RPC connection:
42
+
43
+ 1. The CLI hits `/protected` with no payment.
44
+ 2. The middleware emits a `402 Payment Required` carrying the x402 v2
45
+ `PAYMENT-REQUIRED` envelope (base64). The envelope embeds AgentTrust's
46
+ policy hints in `extra.agentTrust`.
47
+ 3. Pay.sh signs the payment locally (Surfpool sandbox) and retries with
48
+ `PAYMENT-SIGNATURE`.
49
+ 4. The middleware:
50
+ - calls `PaySh.parseRequest` → `VerifyContext`
51
+ - calls `decide(ctx)` — the demo policy maps the `X-Demo-Payer-Agent`
52
+ header to a counterparty tier and compares against `minTier=2`
53
+ - on **Allow**: validates the proof shape, emits a synthetic feedback
54
+ CPI signature, and forwards to the resource handler
55
+ - on **Deny**: returns 402 with the reason code from the gate decision
56
+
57
+ ## Three demo counterparties
58
+
59
+ The `defaultCounterpartyTable()` in `src/index.ts` seeds three deterministic
60
+ agent PDAs:
61
+
62
+ | header value (X-Demo-Payer-Agent) | tier | expected outcome |
63
+ |--|--|--|
64
+ | (output of `seed("tier0")`) | 0 | **402 Deny** — `CounterpartyTierBelowMin` |
65
+ | (output of `seed("tier1")`) | 1 | **402 Deny** — `CounterpartyTierBelowMin` |
66
+ | (output of `seed("tier3")`) | 3 | **200 Allow** |
67
+
68
+ Hit `GET /health` for the actual base58 strings. Then drive each path with
69
+ the matching header.
70
+
71
+ ## Run
72
+
73
+ ```bash
74
+ # from repo root
75
+ pnpm install
76
+ pnpm --filter ./examples/pay-sh-demo build
77
+ pnpm --filter ./examples/pay-sh-demo dev
78
+ # server listens on :3402
79
+
80
+ # in another shell — Allow path (tier 3)
81
+ PAYER=$(curl -s http://localhost:3402/health | jq -r '.counterparties[2].agent')
82
+ pay --sandbox curl -H "X-Demo-Payer-Agent: $PAYER" http://localhost:3402/protected
83
+
84
+ # Deny path (tier 0)
85
+ PAYER=$(curl -s http://localhost:3402/health | jq -r '.counterparties[0].agent')
86
+ pay --sandbox curl -H "X-Demo-Payer-Agent: $PAYER" http://localhost:3402/protected
87
+ ```
88
+
89
+ If the `pay` CLI isn't installed, the integration tests in `test/` exercise
90
+ the same flow via supertest with synthesised x402 challenge / proof bodies.
91
+
92
+ ```bash
93
+ pnpm --filter ./examples/pay-sh-demo test
94
+ ```
95
+
96
+ ## Configuration
97
+
98
+ | env var | default | meaning |
99
+ |--|--|--|
100
+ | `PORT` | `3402` | HTTP port |
101
+ | `NETWORK` | `solana-devnet` | network slug — must match Pay.sh's `--sandbox`/`--mainnet` flag |
102
+ | `MINT` | USDC mainnet | SPL mint advertised in the `extra.asset` field |
103
+
104
+ ## Two modes: demo vs production
105
+
106
+ The demo ships **two boot paths**:
107
+
108
+ ### `createDemoApp` (default `pnpm dev`)
109
+
110
+ Synthesises chain interactions in-process — no Solana RPC needed,
111
+ deterministic fixtures. Useful for CI smoke and local iteration. Three
112
+ counterparty tiers are seeded from a static table; payment proofs are
113
+ synthetic; `emit_feedback` returns deterministic signatures.
114
+
115
+ ### `createRealDemoApp` (used by `demo.agenttrust.tech` in production)
116
+
117
+ Real Anchor `Program<TrustGate>` wired to live devnet. Real
118
+ `validateOnChainTx` parses signed VersionedTransactions via RPC. Real
119
+ `emitFeedbackCpi` lands `FeedbackEmissionLog` PDAs on chain. Real
120
+ `simulateGatePayment` calls the deployed `policy_vault` program for every
121
+ verify request.
122
+
123
+ The hosted demo at `https://demo.agenttrust.tech` runs `createRealDemoApp`.
124
+ Every `/protected` call traversing all three counterparty tiers writes a
125
+ real on-chain artifact. The Phase C smoke trace
126
+ ([`devnet-smoke.json`](./devnet-smoke.json)) was captured from this exact
127
+ boot path against devnet.
128
+
129
+ ## Adding to the demo
130
+
131
+ - New counterparty tier: append to `defaultCounterpartyTable()` in
132
+ `src/index.ts`.
133
+ - New gated route: import `paymentMiddleware` and mount it next to
134
+ `/protected`.
135
+ - Real chain wiring: build a deps factory that returns the same `PayShDeps`
136
+ shape, replace `makeDemoPayShDeps()` in `createDemoApp`.
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Production `PayShDeps` factory — wires real Anchor + RPC into the
3
+ * adapter. Companion to `deps.ts` (the in-memory mock) for the
4
+ * INTEGRATION=1 path.
5
+ *
6
+ * Real chain dependencies:
7
+ * - validateOnChainTx → trustgate-sdk's makeValidateOnChainTx (parses
8
+ * VersionedTransaction, polls connection.getSignatureStatus)
9
+ * - emitFeedbackCpi → trustgate-sdk's makeEmitFeedbackCpi (Anchor
10
+ * methods builder, signed by facilitator keypair)
11
+ * - priorEmissionLookup → trustgate-sdk's makePriorEmissionLookup
12
+ * (fetches FeedbackEmissionLog PDA + recovers signature via
13
+ * getSignaturesForAddress)
14
+ *
15
+ * Quantu account resolution: the demo expects `resolveQuantu(payeeAgent)`
16
+ * to return the bundle of Quantu accounts (asset, collection, optional
17
+ * ATOM) for the given payee agent. For the integration test we use a
18
+ * static map (the demo's payee Quantu accounts are pre-registered or
19
+ * mocked as cloned mainnet accounts under `anchor test`).
20
+ */
21
+
22
+ import { AnchorProvider, Idl, Program, Wallet } from "@coral-xyz/anchor";
23
+ import { Connection, Keypair, PublicKey } from "@solana/web3.js";
24
+
25
+ import {
26
+ DEFAULT_DEVNET_QUANTU_IDS,
27
+ DEFAULT_DEVNET_PROGRAM_IDS,
28
+ MAINNET_QUANTU_IDS,
29
+ QuantuFeedbackAccounts,
30
+ QuantuProgramIds,
31
+ deriveQuantuFeedbackAccounts,
32
+ loadTrustGate,
33
+ makeEmitFeedbackCpi,
34
+ makePriorEmissionLookup,
35
+ makeValidateOnChainTx,
36
+ } from "@agenttrust-sdk/trustgate";
37
+
38
+ import {
39
+ PayShDeps,
40
+ ReplayCache,
41
+ signEnvelope,
42
+ } from "@agenttrust/trustgate-server";
43
+
44
+ export interface MakeRealPayShDepsArgs {
45
+ /** RPC endpoint (e.g. https://api.devnet.solana.com). */
46
+ readonly rpcUrl: string;
47
+ /** Network slug — gates the adapter against mismatched challenges. */
48
+ readonly signingNetwork: string;
49
+ /** Facilitator keypair — payer for emit_feedback, signer of decisions. */
50
+ readonly facilitator: Keypair;
51
+ /** Quantu account resolver. The integration test wires a static map. */
52
+ readonly resolveQuantu: (payeeAgent: PublicKey) => Promise<QuantuFeedbackAccounts>;
53
+ /** Optional override of trustgate program ID (mainnet vs devnet). */
54
+ readonly trustgateProgramId?: PublicKey;
55
+ /** Optional Quantu program IDs override. Default = devnet (matches
56
+ * programs/trustgate/src/constants.rs). Use MAINNET_QUANTU_IDS when
57
+ * running under `anchor test` (clones mainnet pubkeys). */
58
+ readonly quantuPrograms?: QuantuProgramIds;
59
+ /** Optional replay cache override (defaults to a fresh in-memory LRU). */
60
+ readonly replayCache?: ReplayCache;
61
+ /** Optional locally-loaded Anchor IDL. When set, the demo skips the
62
+ * on-chain IDL fetch (useful when the program is deployed but the IDL
63
+ * hasn't been published via `anchor idl init`). */
64
+ readonly trustgateIdl?: Idl;
65
+ }
66
+
67
+ export interface RealPayShDepsBundle {
68
+ readonly deps: PayShDeps;
69
+ readonly connection: Connection;
70
+ readonly trustgate: Program;
71
+ readonly replayCache: ReplayCache;
72
+ }
73
+
74
+ /**
75
+ * Build a `PayShDeps` bundle backed by real Solana RPC + Anchor.
76
+ *
77
+ * Loads the trustgate IDL from chain (the program must be deployed at
78
+ * `trustgateProgramId` — defaults to devnet). Quantu account resolution is
79
+ * caller-supplied so the demo can plug in static fixtures or a real
80
+ * registry-walk strategy.
81
+ */
82
+ export async function makeRealPayShDeps(
83
+ args: MakeRealPayShDepsArgs,
84
+ ): Promise<RealPayShDepsBundle> {
85
+ const trustgateId = args.trustgateProgramId ?? DEFAULT_DEVNET_PROGRAM_IDS.trustGate;
86
+
87
+ const connection = new Connection(args.rpcUrl, "confirmed");
88
+ const wallet = new Wallet(args.facilitator);
89
+ const provider = new AnchorProvider(connection, wallet, { commitment: "confirmed" });
90
+ const trustgate = args.trustgateIdl
91
+ ? new Program(args.trustgateIdl, provider)
92
+ : await loadTrustGate(provider, trustgateId);
93
+
94
+ const validateOnChainTx = makeValidateOnChainTx({ connection });
95
+ const quantuPrograms = args.quantuPrograms ?? DEFAULT_DEVNET_QUANTU_IDS;
96
+ const emitFeedbackCpi = makeEmitFeedbackCpi({
97
+ trustgate,
98
+ trustgateId,
99
+ agentRegistryId: quantuPrograms.agentRegistry,
100
+ facilitator: args.facilitator,
101
+ resolveQuantu: args.resolveQuantu,
102
+ });
103
+ const priorEmissionLookup = makePriorEmissionLookup({
104
+ trustgate,
105
+ trustgateId,
106
+ connection,
107
+ });
108
+
109
+ const replayCache = args.replayCache ?? new ReplayCache();
110
+
111
+ const deps: PayShDeps = {
112
+ signingNetwork: args.signingNetwork,
113
+ feePayer: args.facilitator.publicKey,
114
+ validateOnChainTx,
115
+ emitFeedbackCpi,
116
+ priorEmissionLookup,
117
+ replayCache,
118
+ signDecision: (bytes: Uint8Array) =>
119
+ signEnvelope(bytes, args.facilitator.secretKey),
120
+ };
121
+
122
+ return { deps, connection, trustgate, replayCache };
123
+ }
124
+
125
+ /**
126
+ * Convenience: build a static Quantu resolver from a Map<payeeAgentB58, accounts>.
127
+ * Use this when the demo runs against a small fixed counterparty set.
128
+ */
129
+ export function staticQuantuResolver(
130
+ table: ReadonlyMap<string, { asset: PublicKey; collection: PublicKey; atomEnabled?: boolean }>,
131
+ programs: QuantuProgramIds = DEFAULT_DEVNET_QUANTU_IDS,
132
+ ): (payeeAgent: PublicKey) => Promise<QuantuFeedbackAccounts> {
133
+ return async (payeeAgent) => {
134
+ const entry = table.get(payeeAgent.toBase58());
135
+ if (!entry) {
136
+ throw new Error(
137
+ `staticQuantuResolver: no entry for payeeAgent=${payeeAgent.toBase58()}. ` +
138
+ `Add it to the demo's Quantu account table.`,
139
+ );
140
+ }
141
+ return deriveQuantuFeedbackAccounts({
142
+ programs,
143
+ asset: entry.asset,
144
+ collection: entry.collection,
145
+ atomEnabled: entry.atomEnabled ?? false,
146
+ });
147
+ };
148
+ }
149
+
150
+ export { DEFAULT_DEVNET_QUANTU_IDS, MAINNET_QUANTU_IDS };