@wzrd_sol/eliza-plugin 0.3.2 → 0.5.0

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 CHANGED
@@ -1,14 +1,28 @@
1
1
  # @wzrd_sol/eliza-plugin
2
2
 
3
- ElizaOS plugin for WZRD Agent Intel x402 firewall, free preflight checks before spends,
4
- paid trust receipts (V6 + ERC-8004), and the earn loop on Solana.
3
+ ElizaOS plugin for **WZRD Agent Intel** on the Solana x402 marketplace:
4
+ free pre-spend checks, free merchant graph card, paid V6 trust receipt, offline verify.
5
+ Also ships the **legacy** AO/CCM earn loop against `api.twzrd.xyz`.
6
+
7
+ ## Buyer sequence (marketplace default)
8
+
9
+ Before any x402 spend:
10
+
11
+ 1. **Free preflight** - `WZRD_INTEL_PREFLIGHT` / `preSpendGate` - ReadinessCard `allow` / `warn` / `block`
12
+ 2. **Free merchant_card** - `WZRD_MERCHANT_CARD` (or inside `preSpendGate`) - if `wash_flagged: true`, **do not pay** (default)
13
+ 3. **Optional paid trust** - `WZRD_INTEL_TRUST` (~0.05 USDC) - full score + **signed V6 receipt**
14
+ 4. **Offline verify** - `WZRD_VERIFY_RECEIPT`
15
+
16
+ This plugin exposes **actions + SDK helpers**. It does **not** auto-intercept every wallet signature.
17
+ Wire `preSpendGate` / actions into your spend path, or compose with standalone `twzrd-x402-gate` on a paying fetch.
5
18
 
6
19
  ## 3-line quickstart
7
20
 
8
21
  ```typescript
9
22
  import wzrdPlugin from '@wzrd_sol/eliza-plugin';
10
23
  const agent = new AgentRuntime({ plugins: [wzrdPlugin] });
11
- // "Preflight seller JUP6Lkb... at 0.25 USDC" allow/warn/block, free, no wallet
24
+ // "Preflight seller JUP6Lkb... at 0.25 USDC" -> allow/warn/block, free, no wallet
25
+ // "Merchant card for GFpLvoc..." -> wash_flagged refuse default
12
26
  ```
13
27
 
14
28
  ## Install
@@ -17,21 +31,30 @@ const agent = new AgentRuntime({ plugins: [wzrdPlugin] });
17
31
  npm install @wzrd_sol/eliza-plugin
18
32
  ```
19
33
 
34
+ ## Which package?
35
+
36
+ | Package | Role | Auto-gates every payment? |
37
+ |---------|------|---------------------------|
38
+ | **`@wzrd_sol/eliza-plugin`** (this) | Eliza actions: preflight, merchant_card, paid trust, verify; re-exports SDK `preSpendGate` | No - call-site / LLM actions |
39
+ | **`@wzrd_sol/plugin-trustgate`** | Smaller Eliza provider + `canSpendSafely` (preflight only) | No - opt-in `canSpendSafely` |
40
+ | **`twzrd-x402-gate`** | Framework-agnostic fetch wrapper (preflight + wash refuse on 402) | Only if you wrap fetch |
41
+
20
42
  ## Configuration
21
43
 
22
44
  | Variable | Required | Default | Description |
23
45
  |----------|----------|---------|-------------|
24
- | `WZRD_INTEL_URL` | No | `https://intel.twzrd.xyz` | Agent Intel API (preflight, trust, verify) |
25
- | `WZRD_API_URL` | No | `https://api.twzrd.xyz` | Earn API (infer/report/claim) |
26
- | `SOLANA_PRIVATE_KEY` | Earn lane only | | JSON array of secret key bytes for agent Ed25519 auth |
46
+ | `WZRD_INTEL_URL` | No | `https://intel.twzrd.xyz` | Agent Intel API (preflight, merchant_card, trust, verify) |
47
+ | `WZRD_API_URL` | No | `https://api.twzrd.xyz` | Earn API (infer/report/claim) - legacy lane |
48
+ | `SOLANA_PRIVATE_KEY` | Earn lane only | - | JSON array of secret key bytes for agent Ed25519 auth |
27
49
 
28
50
  ## Intel actions (primary)
29
51
 
30
52
  | Action | Auth/Pay | Description |
31
53
  |--------|----------|-------------|
32
54
  | `WZRD_INTEL_PREFLIGHT` | Free | ReadinessCard: `decision`, `trust_score`, `can_spend`, `caveats`, `preflight_id` |
33
- | `WZRD_INTEL_TRUST` | x402 (~0.05 USDC) | Paid trust payload + V6 signed receipt + ERC-8004 `reputation_credential` |
34
- | `WZRD_VERIFY_RECEIPT` | Free (offline) | Recompute leaf + Ed25519 verify; no network when pubkey is known |
55
+ | `WZRD_MERCHANT_CARD` | Free | Graph card: `wash_flagged`, tier, catalog join; **default refuse if wash** |
56
+ | `WZRD_INTEL_TRUST` | x402 (~0.05 USDC) | Paid trust payload + **V6** signed receipt + ERC-8004 `reputation_credential` |
57
+ | `WZRD_VERIFY_RECEIPT` | Free (offline) | Recompute leaf + Ed25519 verify; V6 primary (older V5 still accepted) |
35
58
 
36
59
  ### Preflight (free, no wallet)
37
60
 
@@ -56,52 +79,78 @@ Decision: allow
56
79
  Trust score: 72
57
80
  Can spend: yes
58
81
  Preflight ID: pf_abc123
59
- Paid deep dive available (0.05 USDC) use WZRD_INTEL_TRUST
82
+ Paid deep dive available (0.05 USDC) - use WZRD_INTEL_TRUST
60
83
  ```
61
84
 
62
- ### Guard pattern: fire-before-pay with `withTwzrdGuard`
63
-
64
- For agents that call x402-gated URLs directly (not via pre-known seller wallet), pair this
65
- plugin with `twzrd-x402-gate` to intercept 402s before any spend:
85
+ ### Merchant card (free wash / demand-quality gate)
66
86
 
67
87
  ```typescript
68
- import wzrdPlugin from '@wzrd_sol/eliza-plugin';
69
- import { withTwzrdGuard } from 'twzrd-x402-gate';
70
- import { createAgentcashFetch } from 'agentcash';
88
+ import { merchantCardAction, fetchMerchantCard } from '@wzrd_sol/eliza-plugin';
71
89
 
72
- // Wrap the paying fetch — guard runs preflight on every 402 before USDC moves.
73
- const x402Fetch = createAgentcashFetch({ apiKey: process.env.AGENTCASH_API_KEY });
74
- const safeFetch = withTwzrdGuard(x402Fetch, {
75
- autoReceipt: true, // auto-buy $0.05 TWZRD receipt on warn/allow
76
- x402Fetch,
77
- });
90
+ // Action (LLM-callable):
91
+ // "Merchant card for GFpLvocNdEjnSsLH3VJQL6wGcjGxTbUBrj6fqN3Qe1Gs"
78
92
 
79
- // Wire safeFetch into any tool or skill that calls paid resources:
80
- const response = await safeFetch('https://api.exa.ai/search');
81
- // decision=block throws before payment
82
- // decision=warn/allow: payment proceeds, TWZRD receipt captured
93
+ // Programmatic:
94
+ const card = await fetchMerchantCard(sellerPubkey);
95
+ if (card?.wash_flagged) return 'refuse dirty pay_to';
96
+ // card unreachable -> fail-open (do not invent wash); use preflight decision only
83
97
  ```
84
98
 
85
- Guard flow:
86
- 1. `safeFetch` hits the resource, gets HTTP 402.
87
- 2. `withTwzrdGuard` reads `accepts[0].payTo` (seller wallet).
88
- 3. Calls `POST /v1/intel/preflight` — free, no auth.
89
- 4. `block` - throws, no payment made.
90
- 5. `warn/allow` - returns the 402 for the x402 client to pay.
99
+ Catalog enrichment is listing metadata only - never overrides wash.
91
100
 
92
- ### Pre-spend gate (programmatic)
101
+ ### Pre-spend gate (programmatic - both free checks)
93
102
 
94
103
  ```typescript
95
- import { preSpendGate, fetchIntelTrust } from '@wzrd_sol/eliza-plugin';
104
+ import { preSpendGate, fetchIntelTrust, fetchMerchantCard } from '@wzrd_sol/eliza-plugin';
96
105
 
97
- // Gate before paying:
98
- const gate = await preSpendGate({ seller_wallet: sellerPubkey });
106
+ // Free preflight + free merchant_card wash refuse (default on):
107
+ const gate = await preSpendGate({ seller_wallet: sellerPubkey, price_usdc: 0.25 });
99
108
  if (!gate.allow) return `Blocked (${gate.decision}): ${gate.reason}`;
109
+ // gate.washFlagged === true was refuse default; null = card gap (fail-open)
100
110
 
101
111
  // Then pay and get the receipt:
102
112
  const trust = await fetchIntelTrust(sellerPubkey, { fetchImpl: myX402Fetch });
103
113
  ```
104
114
 
115
+ **Default:** `refuseWashFlagged: true` - if free `merchant_card.wash_flagged`, do not pay.
116
+ Soft cap: `{ washMaxUsdc: 0.05 }`. Opt out: `{ refuseWashFlagged: false }`.
117
+
118
+ ### Guard pattern: fire-before-pay with `installTwzrdAutoGate` (default-on)
119
+
120
+ For agents that call x402-gated URLs directly (not via a pre-known seller wallet), pair this
121
+ plugin with standalone **`twzrd-x402-gate`** (separate package - not bundled here) to intercept
122
+ 402s before any spend — and register the result as the plugin's paying fetch in one call:
123
+
124
+ ```typescript
125
+ import wzrdPlugin, { installTwzrdAutoGate } from '@wzrd_sol/eliza-plugin';
126
+ import { wrapFetchWithPayment } from '@x402/svm';
127
+
128
+ // Guards the raw fetch (free preflight + free merchant_card wash refuse), hands the guarded
129
+ // fetch to your x402 client, registers the result as the module paying fetch — a blocked or
130
+ // wash-flagged seller throws before your client ever signs.
131
+ installTwzrdAutoGate((guarded) => wrapFetchWithPayment(guarded, buyerWallet));
132
+
133
+ const agent = new AgentRuntime({ plugins: [wzrdPlugin] });
134
+ // WZRD_INTEL_TRUST and any tool/skill using resolvePayingFetch() now goes through the guard.
135
+ ```
136
+
137
+ `payWrap` (the function you pass in) receives the **guarded** fetch — the guard has already
138
+ run by the time your client sees a 402. Building the composition the other way round (guarding
139
+ an already-paying client, e.g. one that resolves 402s internally and returns 200) is a no-op;
140
+ see `twzrd-x402-gate`'s Compatibility note. Opt out with `TWZRD_AUTO_GATE=0` (env) or
141
+ `{ disabled: true }`.
142
+
143
+ Guard flow (in `twzrd-x402-gate`, not inside this plugin):
144
+ 1. The raw fetch hits the resource, gets HTTP 402.
145
+ 2. The guard reads `accepts[0].payTo` (seller wallet).
146
+ 3. Free `POST /v1/intel/preflight` — `decision=block` / score floor throws, `payWrap`'s client never signs.
147
+ 4. Free `GET /v1/intel/merchant_card/{payTo}` — `wash_flagged:true` refuses by default (only tightens step 3).
148
+ 5. Otherwise returns the 402 to `payWrap`'s client, which pays normally.
149
+
150
+ For manual composition (managing the raw/paying split yourself) or `autoReceipt`/`escalateOnWarn`
151
+ options, use `withTwzrdGuard` from `twzrd-x402-gate` directly and pass the result to `setPayingFetch`
152
+ — see that package's README.
153
+
105
154
  ### Paid trust receipt (agentcash)
106
155
 
107
156
  ```typescript
@@ -112,7 +161,7 @@ setPayingFetch(createAgentcashFetch({ apiKey: process.env.AGENTCASH_API_KEY }));
112
161
 
113
162
  const agent = new AgentRuntime({ plugins: [wzrdPlugin] });
114
163
  // "Get the trust receipt for seller JUP6LkbZ..."
115
- // WZRD_INTEL_TRUST: runs free preflight, pays $0.05 USDC, returns VC
164
+ // -> WZRD_INTEL_TRUST: free preflight + merchant_card, then pays $0.05 USDC, returns VC + V6 receipt
116
165
  ```
117
166
 
118
167
  ### Paid trust receipt (PayAI)
@@ -127,8 +176,9 @@ setPayingFetch((url, init) => payai.fetch(url, init));
127
176
  const agent = new AgentRuntime({ plugins: [wzrdPlugin] });
128
177
  ```
129
178
 
130
- Without a paying fetch, `WZRD_INTEL_TRUST` returns the HTTP 402 requirements and an
131
- `npx agentcash@latest fetch ...` one-liner to pay manually.
179
+ Without a paying fetch, `WZRD_INTEL_TRUST` returns the HTTP 402 requirements and a
180
+ manual pay one-liner. Caveat: `npx agentcash@latest fetch` has been a known-bad path
181
+ for TWZRD paid trust (fee_payer slot); prefer a wired `setPayingFetch` client.
132
182
 
133
183
  **`WZRD_INTEL_TRUST` response fields:**
134
184
 
@@ -156,12 +206,20 @@ if (vc.distinctCounterparties < 3) return 'warn'; // thin history
156
206
  if (vc.washFactor < 0.5) return 'warn'; // suspicious ring
157
207
  ```
158
208
 
159
- `effectiveTrustScore` is the cross-facilitator wash-adjusted score computed across all known
209
+ `effectiveTrustScore` is the cross-facilitator wash-adjusted score - computed across all known
160
210
  x402 facilitators, not just one settlement path.
161
211
 
212
+ ### Facilitator settle attach (optional host pattern - not an Eliza action)
213
+
214
+ If your x402 client uses TWZRD as facilitator (`https://intel.twzrd.xyz`), successful
215
+ `POST /settle` may return `merchant_attach` + `twzrd_receipt` for the requirements `payTo`
216
+ (best-effort; never voids on-chain settle). Discover via `GET /supported` (`twzrd.merchant_attach`).
217
+ This plugin does not register a settle action - wire facilitator URL in the host payer.
218
+
162
219
  ### Example agent prompts (trust)
163
220
 
164
221
  - `"Preflight Jupiter Quote Preview before I pay 0.25 USDC to 6EF8rrect..."`
222
+ - `"Merchant card for GFpLvocNdEjnSsLH3VJQL6wGcjGxTbUBrj6fqN3Qe1Gs"`
165
223
  - `"Get the trust receipt for seller JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"`
166
224
  - `"Is it safe to call the paid intel endpoint on this seller?"`
167
225
  - `"Verify this receipt: {leaf, preimage, signature...}"`
@@ -189,6 +247,7 @@ x402 facilitators, not just one settlement path.
189
247
  import {
190
248
  intelPreflight,
191
249
  fetchIntelTrust,
250
+ fetchMerchantCard,
192
251
  verifyReceipt,
193
252
  preSpendGate,
194
253
  IntelPaymentRequiredError,
@@ -197,6 +256,7 @@ import {
197
256
  import type {
198
257
  ReadinessCard,
199
258
  PreflightResponse,
259
+ MerchantCard,
200
260
  IntelTrustResponse,
201
261
  TwzrdReceipt,
202
262
  } from '@wzrd_sol/eliza-plugin';
@@ -211,8 +271,8 @@ npm run build
211
271
  npm test
212
272
  ```
213
273
 
214
- `npm test` runs live free preflight against `intel.twzrd.xyz`, offline receipt verify, and a
215
- mocked paid trust path.
274
+ `npm test` runs live free preflight against `intel.twzrd.xyz`, free merchant_card path,
275
+ offline receipt verify, and a mocked paid trust path.
216
276
 
217
277
  Manual earn smoke (requires `SOLANA_PRIVATE_KEY`):
218
278
 
@@ -224,9 +284,9 @@ npx tsx test/earn-e2e.ts
224
284
 
225
285
  - [Agent Intel API](https://intel.twzrd.xyz)
226
286
  - [API docs / llms.txt](https://intel.twzrd.xyz/llms.txt)
227
- - [x402 gate (standalone firewall)](https://www.npmjs.com/package/twzrd-x402-gate)
287
+ - [x402 gate (standalone fetch firewall)](https://www.npmjs.com/package/twzrd-x402-gate)
288
+ - [plugin-trustgate (smaller Eliza spend guard)](https://www.npmjs.com/package/@wzrd_sol/plugin-trustgate)
228
289
  - [GOAT plugin](https://www.npmjs.com/package/@wzrd_sol/goat-plugin)
229
- - [TWZRD trust quickstart](https://intel.twzrd.xyz/docs/QUICKSTART.md)
230
290
 
231
291
  ## License
232
292
 
@@ -43,7 +43,8 @@ export const intelPreflightAction = {
43
43
  similes: ['WZRD_PREFLIGHT', 'INTEL_PREFLIGHT', 'READINESS_CARD'],
44
44
  description: 'Free pre-spend ReadinessCard for a seller/resource/price/intent. Returns decision (allow/warn/block), ' +
45
45
  'trust_score, can_spend, caveats, paid_deep_dive upsell, and root_provenance when applicable. ' +
46
- 'Run this before any x402 payment.',
46
+ 'Step 1 of the buyer sequence before any x402 payment; follow with WZRD_MERCHANT_CARD (wash refuse default) ' +
47
+ 'or preSpendGate which runs both free checks.',
47
48
  examples: [
48
49
  [
49
50
  {
@@ -1,7 +1,7 @@
1
1
  /**
2
- * WZRD_INTEL_TRUST — Paid trust payload + signed receipt (V5/V6) via x402-capable
3
- * fetch. Preflight-gated: the free ReadinessCard runs BEFORE the payment and a
4
- * decision=block aborts before any spend (the protocol's preflight-before-pay rule).
2
+ * WZRD_INTEL_TRUST — Paid trust payload + signed V6 receipt via x402-capable
3
+ * fetch. Preflight-gated: free ReadinessCard + free merchant_card wash check run
4
+ * BEFORE payment; decision=block or wash_flagged aborts before any spend.
5
5
  */
6
6
  import type { Action } from '@elizaos/core';
7
7
  export declare const intelTrustAction: Action;
@@ -4,8 +4,9 @@ import { resolvePayingFetch } from '../paying-fetch.js';
4
4
  export const intelTrustAction = {
5
5
  name: 'WZRD_INTEL_TRUST',
6
6
  similes: ['WZRD_TRUST_RECEIPT', 'INTEL_TRUST', 'GET_TRUST_RECEIPT'],
7
- description: 'Paid GET /v1/intel/trust/{pubkey} (~0.05 USDC). Returns trust score + signed twzrd_receipt (V5/V6). ' +
8
- 'Runs the free preflight first and aborts on decision=block before spending. ' +
7
+ description: 'Paid GET /v1/intel/trust/{pubkey} (~0.05 USDC on Solana). Returns renormalized trust score + signed V6 ' +
8
+ 'twzrd_receipt (portable offline proof). Runs free preflight + merchant_card wash check first; ' +
9
+ 'aborts on decision=block or wash_flagged before any spend. ' +
9
10
  'Requires an x402-capable fetchImpl (setPayingFetch or host service). ' +
10
11
  'Surfaces payment requirements if no payer is configured.',
11
12
  examples: [
@@ -24,24 +25,32 @@ export const intelTrustAction = {
24
25
  }
25
26
  const apiBase = getIntelBase(runtime);
26
27
  const baseFetchImpl = resolvePayingFetch(runtime);
27
- // preflight-before-pay: run the FREE ReadinessCard on the counterparty and
28
- // abort on decision=block BEFORE any payment is signed/sent. failOpen=false so
28
+ // preflight-before-pay + wash refuse: FREE ReadinessCard + free merchant_card.
29
+ // Abort on decision=block or wash_flagged before any payment. failOpen=false so
29
30
  // the block-on-block guarantee holds even if the gate errors — a reference
30
- // plugin must demonstrate the safe posture, not bypass it. The preflight call
31
- // is free (the gate only ever reads), so this adds no spend.
31
+ // plugin must demonstrate the safe posture, not bypass it. Free reads only.
32
32
  try {
33
- const gate = await preSpendGate({ seller_wallet: pubkey }, { apiBase, failOpen: false, fetchImpl: baseFetchImpl });
33
+ const gate = await preSpendGate({ seller_wallet: pubkey }, { apiBase, failOpen: false, refuseWashFlagged: true, fetchImpl: baseFetchImpl });
34
34
  if (!gate.allow) {
35
+ const washLine = gate.washFlagged === true
36
+ ? `Wash flagged: yes (merchant_card refuse default)\n`
37
+ : '';
35
38
  await callback?.({
36
39
  text: `Preflight blocked the trust purchase for ${pubkey}.\n` +
37
40
  `Decision: ${gate.decision}${gate.trustScore != null ? `, trust_score=${gate.trustScore}` : ''}\n` +
41
+ washLine +
38
42
  `Reason: ${gate.reason}\n` +
39
43
  `No payment was sent.`,
40
44
  });
41
45
  return {
42
46
  success: false,
43
- error: 'preflight_block',
44
- data: { decision: gate.decision, trustScore: gate.trustScore, reason: gate.reason },
47
+ error: gate.washFlagged === true ? 'wash_flagged' : 'preflight_block',
48
+ data: {
49
+ decision: gate.decision,
50
+ trustScore: gate.trustScore,
51
+ reason: gate.reason,
52
+ washFlagged: gate.washFlagged ?? null,
53
+ },
45
54
  };
46
55
  }
47
56
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * WZRD_MERCHANT_CARD — Free demand-quality graph card for a receive wallet.
3
+ * Includes wash_flagged (buyer refuse default) and optional catalog join.
4
+ */
5
+ import type { Action } from '@elizaos/core';
6
+ export declare const merchantCardAction: Action;
@@ -0,0 +1,85 @@
1
+ import { fetchMerchantCard } from '@wzrd_sol/sdk';
2
+ import { extractPubkey, getIntelBase, withTimeout } from '../intel-helpers.js';
3
+ function formatMerchantCard(card) {
4
+ const lines = [
5
+ `Merchant card for ${card.merchant ?? 'unknown'}`,
6
+ `In corpus: ${card.in_corpus ? 'yes' : 'no'}`,
7
+ `Wash flagged: ${card.wash_flagged === true ? 'YES — default refuse pay' : card.wash_flagged === false ? 'no' : 'unknown'}`,
8
+ ];
9
+ if (card.wash_label)
10
+ lines.push(`Wash label: ${card.wash_label}`);
11
+ if (card.provider_reputation_tier)
12
+ lines.push(`Tier: ${card.provider_reputation_tier}`);
13
+ if (card.unique_payers_90d != null)
14
+ lines.push(`Unique payers (90d): ${card.unique_payers_90d}`);
15
+ if (card.offering_status)
16
+ lines.push(`Offering: ${card.offering_status}`);
17
+ if (card.catalog_enriched) {
18
+ const name = card.catalog && typeof card.catalog === 'object' && 'name' in card.catalog
19
+ ? String(card.catalog.name ?? '')
20
+ : '';
21
+ lines.push(`Catalog enriched: yes${name ? ` (${name})` : ''} — listing only, not quality proof`);
22
+ }
23
+ else {
24
+ lines.push('Catalog enriched: no (graph only)');
25
+ }
26
+ if (card.wash_flagged === true) {
27
+ lines.push('Policy: do not pay this pay_to (trustless default). Cap only if operator set washMaxUsdc.');
28
+ }
29
+ return lines.join('\n');
30
+ }
31
+ export const merchantCardAction = {
32
+ name: 'WZRD_MERCHANT_CARD',
33
+ similes: ['WZRD_MERCHANT', 'MERCHANT_CARD', 'INTEL_MERCHANT_CARD', 'CHECK_WASH'],
34
+ description: 'Free GET merchant demand-quality card for a Solana receive wallet (no auth). ' +
35
+ 'Returns wash_flagged, tier, unique payers, catalog join when listed. ' +
36
+ 'Default: if wash_flagged is true, do not pay that pay_to.',
37
+ examples: [
38
+ [
39
+ {
40
+ name: '{{user1}}',
41
+ content: { text: 'Merchant card for 7G73dUxj8Qn4yH4x9zXkKqZ8oKqZ8oKqZ8o' },
42
+ },
43
+ {
44
+ name: '{{agentName}}',
45
+ content: { text: 'Merchant card: wash_flagged YES — default refuse pay' },
46
+ },
47
+ ],
48
+ ],
49
+ validate: async () => true,
50
+ handler: async (runtime, message, _state, _opt, callback) => {
51
+ const content = (message.content ?? {});
52
+ const pubkey = extractPubkey(content);
53
+ if (!pubkey) {
54
+ await callback?.({
55
+ text: 'Provide a merchant/seller wallet (32-44 char base58) for merchant_card.',
56
+ });
57
+ return { success: false, error: 'Missing pubkey' };
58
+ }
59
+ const apiBase = getIntelBase(runtime);
60
+ try {
61
+ const card = await withTimeout(() => fetchMerchantCard(pubkey, { apiBase }));
62
+ if (!card) {
63
+ await callback?.({
64
+ text: `Merchant card unavailable for ${pubkey} (network or invalid). ` +
65
+ `Fail-open: do not invent wash_flagged; use WZRD_INTEL_PREFLIGHT decision only.`,
66
+ });
67
+ return { success: false, error: 'merchant_card_unavailable' };
68
+ }
69
+ const text = formatMerchantCard(card);
70
+ await callback?.({ text });
71
+ return {
72
+ success: true,
73
+ data: {
74
+ ...card,
75
+ refuse_pay: card.wash_flagged === true,
76
+ },
77
+ };
78
+ }
79
+ catch (err) {
80
+ const msg = err instanceof Error ? err.message : String(err);
81
+ await callback?.({ text: `Merchant card failed: ${msg}` });
82
+ return { success: false, error: msg };
83
+ }
84
+ },
85
+ };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WZRD_VERIFY_RECEIPT — Offline leaf + Ed25519 verification (no network).
3
- * Handles both V5 and V6 receipts; the SDK selects the leaf binding from the
4
- * receipt's domain (V6 binds the reputation_* provenance fields into the leaf).
3
+ * Primary surface is V6 (reputation leaf). Older V5 receipts still verify when
4
+ * presented; the SDK selects the leaf binding from the receipt domain.
5
5
  */
6
6
  import type { Action } from '@elizaos/core';
7
7
  export declare const verifyReceiptAction: Action;
@@ -3,11 +3,11 @@ import { getIntelBase, parseReceipt, withTimeout } from '../intel-helpers.js';
3
3
  export const verifyReceiptAction = {
4
4
  name: 'WZRD_VERIFY_RECEIPT',
5
5
  similes: ['WZRD_VERIFY', 'VERIFY_TWZRD_RECEIPT', 'CHECK_RECEIPT'],
6
- description: 'Offline verify a TwzrdReceipt (V5 or V6): recompute keccak leaf from preimage and check Ed25519 signature ' +
7
- 'against the published TWZRD key. No network required when trustedPubkey is known.',
6
+ description: 'Offline verify a TwzrdReceipt (V6 primary; older V5 still accepted): recompute keccak leaf from preimage ' +
7
+ 'and check Ed25519 signature against the published TWZRD key. No network required when trustedPubkey is known.',
8
8
  examples: [
9
9
  [
10
- { name: '{{user1}}', content: { text: 'Verify this receipt: {"version":"v5","leaf":"0x...","preimage":{...}}' } },
10
+ { name: '{{user1}}', content: { text: 'Verify this receipt: {"version":"v6","leaf":"0x...","preimage":{...}}' } },
11
11
  { name: '{{agentName}}', content: { text: 'Receipt valid: leaf OK, signature OK.' } },
12
12
  ],
13
13
  ],
package/dist/index.d.ts CHANGED
@@ -2,8 +2,11 @@
2
2
  * @wzrd_sol/eliza-plugin — WZRD Agent Intel + Earn Loop for ElizaOS
3
3
  *
4
4
  * Intel lane (default https://intel.twzrd.xyz):
5
- * WZRD_INTEL_PREFLIGHT → WZRD_INTEL_TRUST → WZRD_VERIFY_RECEIPT
6
- * Paid intel requires caller-supplied x402 fetch via setPayingFetch().
5
+ * WZRD_INTEL_PREFLIGHT → WZRD_MERCHANT_CARD → WZRD_INTEL_TRUST → WZRD_VERIFY_RECEIPT
6
+ * Paid intel requires a caller-supplied x402 fetch either setPayingFetch(payingFetch)
7
+ * (already-composed, unguarded) or installTwzrdAutoGate(payWrap) (default-on: guards the
8
+ * raw fetch before your client signs, then registers it the same way).
9
+ * Default: preSpendGate refuses wash_flagged pay_to (free merchant_card).
7
10
  *
8
11
  * Earn lane (default https://api.twzrd.xyz):
9
12
  * WZRD_INFER → WZRD_REPORT → WZRD_EARN → WZRD_CLAIM / WZRD_REWARDS
@@ -20,14 +23,15 @@ import { earnAction } from './actions/earn.js';
20
23
  import { claimAction } from './actions/claim.js';
21
24
  import { rewardsAction } from './actions/rewards.js';
22
25
  import { intelPreflightAction } from './actions/intel-preflight.js';
26
+ import { merchantCardAction } from './actions/merchant-card.js';
23
27
  import { intelTrustAction } from './actions/intel-trust.js';
24
28
  import { verifyReceiptAction } from './actions/verify-receipt.js';
25
29
  export declare const wzrdPlugin: Plugin;
26
30
  export default wzrdPlugin;
27
- export { intelPreflightAction, intelTrustAction, verifyReceiptAction, earnAction, inferAction, reportAction, claimAction, rewardsAction, };
31
+ export { intelPreflightAction, merchantCardAction, intelTrustAction, verifyReceiptAction, earnAction, inferAction, reportAction, claimAction, rewardsAction, };
28
32
  export { getWzrdClient, clearClientCache, getIntelApiBase, getIntelClient } from './client-factory.js';
29
- export { setPayingFetch, clearPayingFetch, resolvePayingFetch } from './paying-fetch.js';
33
+ export { setPayingFetch, clearPayingFetch, resolvePayingFetch, installTwzrdAutoGate, } from './paying-fetch.js';
30
34
  export { WzrdClient } from './client.js';
31
35
  export type { InferResult, ReportResult, RewardsBalance, ClaimResult } from './client.js';
32
- export { IntelPaymentRequiredError, intelPreflight, fetchIntelTrust, verifyReceipt, preSpendGate, intelTrustUrl, TRUSTED_RECEIPT_PUBKEY, INTEL_TRUST_PRICE_USDC, } from '@wzrd_sol/sdk';
33
- export type { ReadinessCard, PreflightInput, PreflightResponse, TwzrdReceipt, IntelTrustResponse, VerifyReceiptResult, X402PaymentRequired, } from '@wzrd_sol/sdk';
36
+ export { IntelPaymentRequiredError, intelPreflight, fetchIntelTrust, fetchMerchantCard, verifyReceipt, preSpendGate, intelTrustUrl, TRUSTED_RECEIPT_PUBKEY, INTEL_TRUST_PRICE_USDC, } from '@wzrd_sol/sdk';
37
+ export type { ReadinessCard, PreflightInput, PreflightResponse, MerchantCard, TwzrdReceipt, IntelTrustResponse, VerifyReceiptResult, X402PaymentRequired, } from '@wzrd_sol/sdk';
package/dist/index.js CHANGED
@@ -4,15 +4,18 @@ import { earnAction } from './actions/earn.js';
4
4
  import { claimAction } from './actions/claim.js';
5
5
  import { rewardsAction } from './actions/rewards.js';
6
6
  import { intelPreflightAction } from './actions/intel-preflight.js';
7
+ import { merchantCardAction } from './actions/merchant-card.js';
7
8
  import { intelTrustAction } from './actions/intel-trust.js';
8
9
  import { verifyReceiptAction } from './actions/verify-receipt.js';
9
10
  export const wzrdPlugin = {
10
11
  name: 'wzrd',
11
- description: 'WZRD Agent Intel — free ReadinessCard preflight (gates spends before paying), x402-paid trust receipts ' +
12
- '(V5/V6), offline verification on intel.twzrd.xyz. Also ships the legacy earn loop (infer/report/claim) ' +
13
- 'on api.twzrd.xyz.',
12
+ description: 'WZRD Agent Intel — free ReadinessCard preflight + free merchant_card wash refuse (default), ' +
13
+ 'then optional x402-paid V6 trust receipt (~0.05 USDC) + offline verify on intel.twzrd.xyz. ' +
14
+ 'Buyer sequence is call-site / action-driven (not an auto-interceptor of all payments). ' +
15
+ 'Also ships the legacy earn loop (infer/report/claim) on api.twzrd.xyz.',
14
16
  actions: [
15
17
  intelPreflightAction,
18
+ merchantCardAction,
16
19
  intelTrustAction,
17
20
  verifyReceiptAction,
18
21
  earnAction,
@@ -23,8 +26,8 @@ export const wzrdPlugin = {
23
26
  ],
24
27
  };
25
28
  export default wzrdPlugin;
26
- export { intelPreflightAction, intelTrustAction, verifyReceiptAction, earnAction, inferAction, reportAction, claimAction, rewardsAction, };
29
+ export { intelPreflightAction, merchantCardAction, intelTrustAction, verifyReceiptAction, earnAction, inferAction, reportAction, claimAction, rewardsAction, };
27
30
  export { getWzrdClient, clearClientCache, getIntelApiBase, getIntelClient } from './client-factory.js';
28
- export { setPayingFetch, clearPayingFetch, resolvePayingFetch } from './paying-fetch.js';
31
+ export { setPayingFetch, clearPayingFetch, resolvePayingFetch, installTwzrdAutoGate, } from './paying-fetch.js';
29
32
  export { WzrdClient } from './client.js';
30
- export { IntelPaymentRequiredError, intelPreflight, fetchIntelTrust, verifyReceipt, preSpendGate, intelTrustUrl, TRUSTED_RECEIPT_PUBKEY, INTEL_TRUST_PRICE_USDC, } from '@wzrd_sol/sdk';
33
+ export { IntelPaymentRequiredError, intelPreflight, fetchIntelTrust, fetchMerchantCard, verifyReceipt, preSpendGate, intelTrustUrl, TRUSTED_RECEIPT_PUBKEY, INTEL_TRUST_PRICE_USDC, } from '@wzrd_sol/sdk';
@@ -1,7 +1,24 @@
1
1
  /** x402-capable fetch injection for paid intel actions. No embedded wallet. */
2
2
  import type { IAgentRuntime } from '@elizaos/core';
3
+ import { type InstallAutoGateOptions, type PayWrap } from 'twzrd-x402-gate';
3
4
  /** Host supplies an x402-capable fetch (agentcash, twzrd-x402-gate, etc.) before runtime creation. */
4
5
  export declare function setPayingFetch(f: typeof fetch): void;
6
+ /**
7
+ * Default-on replacement for `setPayingFetch(payWrap(rawFetch))`: guards the raw fetch
8
+ * with the free TWZRD preflight BEFORE handing it to your x402 client's `payWrap`, so a
9
+ * blocked seller is refused before your client ever signs — then registers the result as
10
+ * the module paying fetch (same slot `setPayingFetch` writes to).
11
+ *
12
+ * Opt out with `TWZRD_AUTO_GATE=0` (env) or `{ disabled: true }`.
13
+ *
14
+ * @example
15
+ * import { installTwzrdAutoGate } from '@wzrd_sol/eliza-plugin';
16
+ * import { wrapFetchWithPayment } from '@x402/svm';
17
+ *
18
+ * installTwzrdAutoGate((guarded) => wrapFetchWithPayment(guarded, buyerWallet));
19
+ * const agent = new AgentRuntime({ plugins: [wzrdPlugin] });
20
+ */
21
+ export declare function installTwzrdAutoGate(payWrap: PayWrap, options?: InstallAutoGateOptions): void;
5
22
  export declare function clearPayingFetch(): void;
6
23
  type FetchLike = typeof fetch;
7
24
  /** Resolve paying fetch: module setter > runtime service > runtime.fetch > global fetch. */
@@ -1,8 +1,27 @@
1
+ import { installTwzrdAutoGate as buildAutoGate, } from 'twzrd-x402-gate';
1
2
  let modulePayingFetch = null;
2
3
  /** Host supplies an x402-capable fetch (agentcash, twzrd-x402-gate, etc.) before runtime creation. */
3
4
  export function setPayingFetch(f) {
4
5
  modulePayingFetch = f;
5
6
  }
7
+ /**
8
+ * Default-on replacement for `setPayingFetch(payWrap(rawFetch))`: guards the raw fetch
9
+ * with the free TWZRD preflight BEFORE handing it to your x402 client's `payWrap`, so a
10
+ * blocked seller is refused before your client ever signs — then registers the result as
11
+ * the module paying fetch (same slot `setPayingFetch` writes to).
12
+ *
13
+ * Opt out with `TWZRD_AUTO_GATE=0` (env) or `{ disabled: true }`.
14
+ *
15
+ * @example
16
+ * import { installTwzrdAutoGate } from '@wzrd_sol/eliza-plugin';
17
+ * import { wrapFetchWithPayment } from '@x402/svm';
18
+ *
19
+ * installTwzrdAutoGate((guarded) => wrapFetchWithPayment(guarded, buyerWallet));
20
+ * const agent = new AgentRuntime({ plugins: [wzrdPlugin] });
21
+ */
22
+ export function installTwzrdAutoGate(payWrap, options) {
23
+ setPayingFetch(buildAutoGate(payWrap, options));
24
+ }
6
25
  export function clearPayingFetch() {
7
26
  modulePayingFetch = null;
8
27
  }
@@ -10,7 +10,7 @@
10
10
  import assert from 'node:assert/strict';
11
11
  import { describe, it, before, after } from 'node:test';
12
12
  import { AgentRuntime } from '@elizaos/core';
13
- import wzrdPlugin, { intelPreflightAction, intelTrustAction, verifyReceiptAction, setPayingFetch, clearPayingFetch, getIntelClient, resolvePayingFetch, } from '@wzrd_sol/eliza-plugin';
13
+ import wzrdPlugin, { intelPreflightAction, merchantCardAction, intelTrustAction, verifyReceiptAction, setPayingFetch, clearPayingFetch, getIntelClient, resolvePayingFetch, } from '@wzrd_sol/eliza-plugin';
14
14
  function mockMemory(content) {
15
15
  return {
16
16
  id: '00000000-0000-0000-0000-000000000001',
@@ -43,6 +43,7 @@ describe('wzrdPlugin intel registration + E2E (real runtime load)', () => {
43
43
  it('constructs runtime with plugins and registers intel actions', () => {
44
44
  const names = runtime.actions.map((a) => a.name);
45
45
  assert.ok(names.includes('WZRD_INTEL_PREFLIGHT'), 'preflight must be registered');
46
+ assert.ok(names.includes('WZRD_MERCHANT_CARD'), 'merchant card must be registered');
46
47
  assert.ok(names.includes('WZRD_INTEL_TRUST'), 'trust must be registered');
47
48
  assert.ok(names.includes('WZRD_VERIFY_RECEIPT'), 'verify must be registered');
48
49
  });
@@ -121,35 +122,115 @@ describe('wzrdPlugin intel registration + E2E (real runtime load)', () => {
121
122
  assert.ok(result.data);
122
123
  });
123
124
  it('PREFLIGHT-BEFORE-PAY: decision=block aborts the trust purchase before any payment', async () => {
124
- // preSpendGate runs the FREE preflight via the SDK's intelPreflight, which uses
125
- // the global fetch (not the injected paying fetch that is reserved for the
126
- // paid leg). So we stub global fetch to return a block ReadinessCard, and put a
127
- // tripwire on the injected paying fetch: if the pay leg runs after a block, the
128
- // tripwire fires and the test fails.
125
+ // preSpendGate runs FREE preflight + merchant_card via global fetch (not the
126
+ // injected paying fetch). Stub both; tripwire on pay leg.
129
127
  const realFetch = globalThis.fetch;
130
128
  let payAttempted = false;
131
129
  setPayingFetch(async () => {
132
130
  payAttempted = true;
133
131
  return { ok: true, status: 200, json: async () => ({}) };
134
132
  });
133
+ globalThis.fetch = (async (input) => {
134
+ const url = String(input);
135
+ if (url.includes('/merchant_card/')) {
136
+ return {
137
+ ok: true,
138
+ status: 200,
139
+ json: async () => ({ wash_flagged: false }),
140
+ };
141
+ }
142
+ return {
143
+ ok: true,
144
+ status: 200,
145
+ json: async () => ({
146
+ readiness_card: { decision: 'block', trust_score: 5, can_spend: false },
147
+ reason: 'seller flagged by corpus',
148
+ }),
149
+ };
150
+ });
151
+ try {
152
+ const callbacks = [];
153
+ const result = await intelTrustAction.handler(mockRuntime(), mockMemory({ pubkey: '4LkEFjJdXARkKx8FBx4LBFa2SvJNmjQpgGDLoJcypZUE' }), undefined, undefined, async (r) => {
154
+ callbacks.push(r.text ?? '');
155
+ return [];
156
+ });
157
+ assert.equal(result?.success, false);
158
+ assert.equal(result?.error, 'preflight_block');
159
+ assert.equal(payAttempted, false, 'payment must NOT be attempted after a block decision');
160
+ assert.match(callbacks.join('\n'), /blocked|No payment was sent/i);
161
+ }
162
+ finally {
163
+ globalThis.fetch = realFetch;
164
+ }
165
+ });
166
+ it('WASH REFUSE: wash_flagged aborts trust purchase even when preflight allows', async () => {
167
+ const realFetch = globalThis.fetch;
168
+ let payAttempted = false;
169
+ setPayingFetch(async () => {
170
+ payAttempted = true;
171
+ return { ok: true, status: 200, json: async () => ({}) };
172
+ });
173
+ globalThis.fetch = (async (input) => {
174
+ const url = String(input);
175
+ if (url.includes('/merchant_card/')) {
176
+ return {
177
+ ok: true,
178
+ status: 200,
179
+ json: async () => ({
180
+ merchant: '4LkEFjJdXARkKx8FBx4LBFa2SvJNmjQpgGDLoJcypZUE',
181
+ wash_flagged: true,
182
+ wash_label: 'fleet_dominated',
183
+ }),
184
+ };
185
+ }
186
+ return {
187
+ ok: true,
188
+ status: 200,
189
+ json: async () => ({
190
+ readiness_card: { decision: 'allow', trust_score: 80, can_spend: true },
191
+ reason: 'preflight decision=allow',
192
+ }),
193
+ };
194
+ });
195
+ try {
196
+ const callbacks = [];
197
+ const result = await intelTrustAction.handler(mockRuntime(), mockMemory({ pubkey: '4LkEFjJdXARkKx8FBx4LBFa2SvJNmjQpgGDLoJcypZUE' }), undefined, undefined, async (r) => {
198
+ callbacks.push(r.text ?? '');
199
+ return [];
200
+ });
201
+ assert.equal(result?.success, false);
202
+ assert.equal(result?.error, 'wash_flagged');
203
+ assert.equal(payAttempted, false, 'payment must NOT run after wash refuse');
204
+ assert.match(callbacks.join('\n'), /wash|No payment was sent/i);
205
+ }
206
+ finally {
207
+ globalThis.fetch = realFetch;
208
+ }
209
+ });
210
+ it('merchant card handler returns wash / catalog fields (mocked)', async () => {
211
+ const realFetch = globalThis.fetch;
135
212
  globalThis.fetch = (async () => ({
136
213
  ok: true,
137
214
  status: 200,
138
215
  json: async () => ({
139
- readiness_card: { decision: 'block', trust_score: 5, can_spend: false },
140
- reason: 'seller flagged by corpus',
216
+ merchant: '4LkEFjJdXARkKx8FBx4LBFa2SvJNmjQpgGDLoJcypZUE',
217
+ in_corpus: true,
218
+ wash_flagged: false,
219
+ wash_label: 'provider_organic_broad',
220
+ catalog_enriched: false,
221
+ offering_status: 'Offering unknown — graph only',
222
+ unique_payers_90d: 12,
141
223
  }),
142
224
  }));
143
225
  try {
144
226
  const callbacks = [];
145
- const result = await intelTrustAction.handler(mockRuntime(), mockMemory({ pubkey: '4LkEFjJdXARkKx8FBx4LBFa2SvJNmjQpgGDLoJcypZUE' }), undefined, undefined, async (r) => {
227
+ const result = await merchantCardAction.handler(mockRuntime(), mockMemory({ pubkey: '4LkEFjJdXARkKx8FBx4LBFa2SvJNmjQpgGDLoJcypZUE' }), undefined, undefined, async (r) => {
146
228
  callbacks.push(r.text ?? '');
147
229
  return [];
148
230
  });
149
- assert.equal(result?.success, false);
150
- assert.equal(result?.error, 'preflight_block');
151
- assert.equal(payAttempted, false, 'payment must NOT be attempted after a block decision');
152
- assert.match(callbacks.join('\n'), /blocked|No payment was sent/i);
231
+ assert.equal(result?.success, true);
232
+ assert.match(callbacks.join('\n'), /Wash flagged: no/i);
233
+ assert.match(callbacks.join('\n'), /graph only/i);
153
234
  }
154
235
  finally {
155
236
  globalThis.fetch = realFetch;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wzrd_sol/eliza-plugin",
3
- "version": "0.3.2",
4
- "description": "WZRD Agent Intel for ElizaOS preflight ReadinessCards, x402-paid signed trust receipts (V6 reputation leaf), offline verification on intel.twzrd.xyz. Also ships the legacy earn loop.",
3
+ "version": "0.5.0",
4
+ "description": "WZRD Agent Intel for ElizaOS. Free buyer sequence: preflight ReadinessCard + merchant_card (wash_flagged refuse default). Paid: GET /v1/intel/trust (0.05 USDC) for signed V6 receipt. Offline verify. installTwzrdAutoGate(payWrap) registers a default-on guarded paying fetch in one call; setPayingFetch / actions / preSpendGate remain available for manual wiring. Also ships the legacy earn loop.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -19,9 +19,10 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@solana/web3.js": "^1.95.0",
22
- "@wzrd_sol/sdk": "^0.4.3",
22
+ "@wzrd_sol/sdk": "^0.4.7",
23
23
  "bs58": "^5.0.0",
24
- "tweetnacl": "^1.0.3"
24
+ "tweetnacl": "^1.0.3",
25
+ "twzrd-x402-gate": "^0.5.0"
25
26
  },
26
27
  "peerDependencies": {
27
28
  "@elizaos/core": "^1.0.0"
@@ -47,6 +48,9 @@
47
48
  "receipt",
48
49
  "reputation",
49
50
  "preflight",
51
+ "merchant_card",
52
+ "wash",
53
+ "marketplace",
50
54
  "ccm",
51
55
  "inference",
52
56
  "earn",
@@ -59,8 +63,8 @@
59
63
  },
60
64
  "repository": {
61
65
  "type": "git",
62
- "url": "git+https://github.com/twzrd-sol/wzrd-final.git",
63
- "directory": "agents/eliza-plugin"
66
+ "url": "git+https://github.com/twzrd-sol/twzrd-trust.git",
67
+ "directory": "eliza-plugin"
64
68
  },
65
69
  "bugs": {
66
70
  "url": "https://github.com/twzrd-sol/twzrd-trust/issues"