@wzrd_sol/eliza-plugin 0.3.1 → 0.3.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.
package/README.md CHANGED
@@ -1,8 +1,15 @@
1
1
  # @wzrd_sol/eliza-plugin
2
2
 
3
- ElizaOS plugin for WZRD Agent Intel and the legacy earn loop on Solana.
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.
4
5
 
5
- **Before any x402 spend:** run `WZRD_INTEL_PREFLIGHT` (free ReadinessCard). Escalate to `WZRD_INTEL_TRUST` only when you need a signed V5 receipt. Verify offline with `WZRD_VERIFY_RECEIPT`.
6
+ ## 3-line quickstart
7
+
8
+ ```typescript
9
+ import wzrdPlugin from '@wzrd_sol/eliza-plugin';
10
+ const agent = new AgentRuntime({ plugins: [wzrdPlugin] });
11
+ // "Preflight seller JUP6Lkb... at 0.25 USDC" → allow/warn/block, free, no wallet
12
+ ```
6
13
 
7
14
  ## Install
8
15
 
@@ -15,93 +22,194 @@ npm install @wzrd_sol/eliza-plugin
15
22
  | Variable | Required | Default | Description |
16
23
  |----------|----------|---------|-------------|
17
24
  | `WZRD_INTEL_URL` | No | `https://intel.twzrd.xyz` | Agent Intel API (preflight, trust, verify) |
18
- | `WZRD_API_URL` | No | `https://api.twzrd.xyz` | Legacy earn API (infer/report/claim) |
25
+ | `WZRD_API_URL` | No | `https://api.twzrd.xyz` | Earn API (infer/report/claim) |
19
26
  | `SOLANA_PRIVATE_KEY` | Earn lane only | — | JSON array of secret key bytes for agent Ed25519 auth |
20
27
 
21
- ### Wiring a paying fetch (intel paid actions)
28
+ ## Intel actions (primary)
22
29
 
23
- The plugin does **not** embed a wallet. Paid `WZRD_INTEL_TRUST` needs an x402-capable `fetch` from the host:
30
+ | Action | Auth/Pay | Description |
31
+ |--------|----------|-------------|
32
+ | `WZRD_INTEL_PREFLIGHT` | Free | ReadinessCard: `decision`, `trust_score`, `can_spend`, `caveats`, `preflight_id` |
33
+ | `WZRD_MERCHANT_CARD` | Free | Graph card: `wash_flagged`, tier, catalog join; default refuse if wash |
34
+ | `WZRD_INTEL_TRUST` | x402 (~0.05 USDC) | Paid trust payload + V6 signed receipt + ERC-8004 `reputation_credential` |
35
+ | `WZRD_VERIFY_RECEIPT` | Free (offline) | Recompute leaf + Ed25519 verify; no network when pubkey is known |
24
36
 
25
- ```typescript
26
- import { AgentRuntime } from '@elizaos/core';
27
- import wzrdPlugin, { setPayingFetch } from '@wzrd_sol/eliza-plugin';
28
- import { agentcashFetch } from 'your-x402-wrapper'; // agentcash, twzrd-x402-gate, etc.
37
+ ### Preflight (free, no wallet)
29
38
 
30
- setPayingFetch(agentcashFetch);
39
+ ```typescript
40
+ import { intelPreflightAction } from '@wzrd_sol/eliza-plugin';
31
41
 
32
- const agent = new AgentRuntime({
33
- plugins: [wzrdPlugin],
34
- settings: {
35
- WZRD_INTEL_URL: 'https://intel.twzrd.xyz',
36
- SOLANA_PRIVATE_KEY: process.env.SOLANA_PRIVATE_KEY,
42
+ // Reads seller_wallet / price_usdc / agent_intent from message content.
43
+ await intelPreflightAction.handler(runtime, {
44
+ content: {
45
+ seller_wallet: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',
46
+ price_usdc: 0.25,
47
+ agent_intent: 'quote preview',
37
48
  },
38
- });
49
+ }, state, opts, callback);
50
+ ```
51
+
52
+ Response (formatted text returned to agent):
53
+
54
+ ```
55
+ ReadinessCard v1
56
+ Decision: allow
57
+ Trust score: 72
58
+ Can spend: yes
59
+ Preflight ID: pf_abc123
60
+ Paid deep dive available (0.05 USDC) — use WZRD_INTEL_TRUST
39
61
  ```
40
62
 
41
- Without a paying fetch, `WZRD_INTEL_TRUST` returns the HTTP 402 requirements and an `npx agentcash@latest fetch ...` one-liner.
63
+ ### Guard pattern: fire-before-pay with `withTwzrdGuard`
42
64
 
43
- ## Usage
65
+ For agents that call x402-gated URLs directly (not via pre-known seller wallet), pair this
66
+ plugin with `twzrd-x402-gate` to intercept 402s before any spend:
44
67
 
45
68
  ```typescript
46
- import { wzrdPlugin } from '@wzrd_sol/eliza-plugin';
47
-
48
- const agent = new AgentRuntime({
49
- plugins: [wzrdPlugin],
69
+ import wzrdPlugin from '@wzrd_sol/eliza-plugin';
70
+ import { withTwzrdGuard } from 'twzrd-x402-gate';
71
+ import { createAgentcashFetch } from 'agentcash';
72
+
73
+ // Wrap the paying fetch — guard runs preflight on every 402 before USDC moves.
74
+ const x402Fetch = createAgentcashFetch({ apiKey: process.env.AGENTCASH_API_KEY });
75
+ const safeFetch = withTwzrdGuard(x402Fetch, {
76
+ autoReceipt: true, // auto-buy $0.05 TWZRD receipt on warn/allow
77
+ x402Fetch,
50
78
  });
79
+
80
+ // Wire safeFetch into any tool or skill that calls paid resources:
81
+ const response = await safeFetch('https://api.exa.ai/search');
82
+ // → decision=block throws before payment
83
+ // → decision=warn/allow: payment proceeds, TWZRD receipt captured
51
84
  ```
52
85
 
53
- Programmatic SDK calls (same types as the plugin) are re-exported:
86
+ Guard flow:
87
+ 1. `safeFetch` hits the resource, gets HTTP 402.
88
+ 2. `withTwzrdGuard` reads `accepts[0].payTo` (seller wallet).
89
+ 3. Calls `POST /v1/intel/preflight` — free, no auth.
90
+ 4. `block` - throws, no payment made.
91
+ 5. `warn/allow` - returns the 402 for the x402 client to pay.
92
+
93
+ ### Pre-spend gate (programmatic)
54
94
 
55
95
  ```typescript
56
- import { intelPreflight, fetchIntelTrust, verifyReceipt, IntelPaymentRequiredError } from '@wzrd_sol/eliza-plugin';
96
+ import { preSpendGate, fetchIntelTrust, fetchMerchantCard } from '@wzrd_sol/eliza-plugin';
97
+
98
+ // Gate before paying (free preflight + free merchant_card wash refuse, default on):
99
+ const gate = await preSpendGate({ seller_wallet: sellerPubkey, price_usdc: 0.25 });
100
+ if (!gate.allow) return `Blocked (${gate.decision}): ${gate.reason}`;
101
+ // gate.washFlagged === true was refuse default; null = card gap (fail-open)
102
+
103
+ // Or inspect the card alone:
104
+ const card = await fetchMerchantCard(sellerPubkey);
105
+ if (card?.wash_flagged) return 'refuse dirty pay_to';
106
+
107
+ // Then pay and get the receipt:
108
+ const trust = await fetchIntelTrust(sellerPubkey, { fetchImpl: myX402Fetch });
57
109
  ```
58
110
 
59
- ## Intel actions (primary)
111
+ **Default:** `refuseWashFlagged: true` — if free `merchant_card.wash_flagged`, do not pay.
112
+ Soft cap: `{ washMaxUsdc: 0.05 }`. Opt out: `{ refuseWashFlagged: false }`.
60
113
 
61
- | Action | Auth/Pay | Description |
62
- |--------|----------|-------------|
63
- | `WZRD_INTEL_PREFLIGHT` | Free | ReadinessCard: decision, trust_score, can_spend, caveats, paid upsell |
64
- | `WZRD_INTEL_TRUST` | x402 (~0.05 USDC) | Paid trust payload + V5 `twzrd_receipt` (needs `setPayingFetch`) |
65
- | `WZRD_VERIFY_RECEIPT` | Free (offline) | Recompute leaf + Ed25519 verify; no network when pubkey is known |
114
+ ### Paid trust receipt (agentcash)
115
+
116
+ ```typescript
117
+ import wzrdPlugin, { setPayingFetch } from '@wzrd_sol/eliza-plugin';
118
+ import { createAgentcashFetch } from 'agentcash';
66
119
 
67
- ### Example prompts
120
+ setPayingFetch(createAgentcashFetch({ apiKey: process.env.AGENTCASH_API_KEY }));
68
121
 
69
- - "Preflight Jupiter Quote Preview before I pay 0.25 USDC to 6EF8rrect..."
70
- - "Get the trust receipt for seller JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"
71
- - "Verify this receipt: {leaf, preimage, signature...}"
72
- - "Is it safe to call the paid intel endpoint on this seller?"
122
+ const agent = new AgentRuntime({ plugins: [wzrdPlugin] });
123
+ // "Get the trust receipt for seller JUP6LkbZ..."
124
+ // WZRD_INTEL_TRUST: runs free preflight, pays $0.05 USDC, returns VC
125
+ ```
73
126
 
74
- ### Free preflight (no wallet)
127
+ ### Paid trust receipt (PayAI)
75
128
 
76
129
  ```typescript
77
- import { intelPreflightAction } from '@wzrd_sol/eliza-plugin';
130
+ import wzrdPlugin, { setPayingFetch } from '@wzrd_sol/eliza-plugin';
131
+ import { PayAIClient } from '@payai/client';
78
132
 
79
- // Handler reads seller_wallet / price_usdc / agent_intent from message content
80
- await intelPreflightAction.handler(runtime, {
81
- content: {
82
- seller_wallet: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',
83
- price_usdc: 0.25,
84
- agent_intent: 'quote preview',
85
- },
86
- }, ...);
133
+ const payai = new PayAIClient({ keypairPath: '~/.config/solana/id.json' });
134
+ setPayingFetch((url, init) => payai.fetch(url, init));
135
+
136
+ const agent = new AgentRuntime({ plugins: [wzrdPlugin] });
137
+ ```
138
+
139
+ Without a paying fetch, `WZRD_INTEL_TRUST` returns the HTTP 402 requirements and an
140
+ `npx agentcash@latest fetch ...` one-liner to pay manually.
141
+
142
+ **`WZRD_INTEL_TRUST` response fields:**
143
+
144
+ ```
145
+ Trust payload for JUP6Lkb...
146
+ Score: 61.8 Paid: yes
147
+ Settlement tx: 4xK3n...
148
+ Reputation credential (ERC-8004 AgentReputationCredential):
149
+ effectiveTrustScore: 62 <- route on this (wash-adjusted)
150
+ trustScore: 72 washFactor: 0.86
151
+ distinctCounterparties: 14 <- cross-facilitator breadth
152
+ corpusScope: cross-facilitator
153
+ version: intel_renorm_v1
154
+ Routing gate: effectiveTrustScore < 30 -> block, 30-60 -> warn, > 60 -> allow
155
+ Receipt v6, leaf: 0x3a4f...
156
+ Use WZRD_VERIFY_RECEIPT to verify offline.
157
+ ```
158
+
159
+ **Routing logic:**
160
+
161
+ ```typescript
162
+ const vc = trust.reputation_credential.credentialSubject;
163
+ if (vc.effectiveTrustScore < 30) return 'block';
164
+ if (vc.distinctCounterparties < 3) return 'warn'; // thin history
165
+ if (vc.washFactor < 0.5) return 'warn'; // suspicious ring
87
166
  ```
88
167
 
168
+ `effectiveTrustScore` is the cross-facilitator wash-adjusted score — computed across all known
169
+ x402 facilitators, not just one settlement path.
170
+
171
+ ### Example agent prompts (trust)
172
+
173
+ - `"Preflight Jupiter Quote Preview before I pay 0.25 USDC to 6EF8rrect..."`
174
+ - `"Get the trust receipt for seller JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"`
175
+ - `"Is it safe to call the paid intel endpoint on this seller?"`
176
+ - `"Verify this receipt: {leaf, preimage, signature...}"`
177
+
89
178
  ## Legacy earn actions
90
179
 
91
180
  | Action | Auth | Description |
92
181
  |--------|------|-------------|
93
182
  | `WZRD_INFER` | Agent Ed25519 | Server-witnessed inference; returns `execution_id` |
94
183
  | `WZRD_REPORT` | Agent Ed25519 | Report outcome with `execution_id` for verified rewards |
95
- | `WZRD_EARN` | Agent Ed25519 | Full infer report rewards check in one action |
184
+ | `WZRD_EARN` | Agent Ed25519 | Full infer -> report -> rewards check in one action |
96
185
  | `WZRD_CLAIM` | Agent Ed25519 | Gasless CCM claim via relay |
97
186
  | `WZRD_REWARDS` | Agent Ed25519 | Pending and lifetime CCM balance |
98
187
 
99
188
  ### Example prompts (earn)
100
189
 
101
- - "Run inference through WZRD: explain quicksort in Python"
102
- - "Earn some CCM on WZRD"
103
- - "Check my WZRD rewards"
104
- - "Claim my CCM"
190
+ - `"Run inference through WZRD: explain quicksort in Python"`
191
+ - `"Earn some CCM on WZRD"`
192
+ - `"Check my WZRD rewards"`
193
+ - `"Claim my CCM"`
194
+
195
+ ## Programmatic SDK usage
196
+
197
+ ```typescript
198
+ import {
199
+ intelPreflight,
200
+ fetchIntelTrust,
201
+ verifyReceipt,
202
+ preSpendGate,
203
+ IntelPaymentRequiredError,
204
+ } from '@wzrd_sol/eliza-plugin';
205
+
206
+ import type {
207
+ ReadinessCard,
208
+ PreflightResponse,
209
+ IntelTrustResponse,
210
+ TwzrdReceipt,
211
+ } from '@wzrd_sol/eliza-plugin';
212
+ ```
105
213
 
106
214
  ## Test
107
215
 
@@ -112,7 +220,8 @@ npm run build
112
220
  npm test
113
221
  ```
114
222
 
115
- `npm test` loads the plugin into a real `@elizaos/core` `AgentRuntime`, runs live free preflight against `intel.twzrd.xyz`, offline receipt verify, and a mocked paid trust path.
223
+ `npm test` runs live free preflight against `intel.twzrd.xyz`, offline receipt verify, and a
224
+ mocked paid trust path.
116
225
 
117
226
  Manual earn smoke (requires `SOLANA_PRIVATE_KEY`):
118
227
 
@@ -123,11 +232,11 @@ npx tsx test/earn-e2e.ts
123
232
  ## Links
124
233
 
125
234
  - [Agent Intel API](https://intel.twzrd.xyz)
126
- - [Legacy API](https://api.twzrd.xyz)
127
- - [SDK](https://www.npmjs.com/package/@wzrd_sol/sdk)
128
- - [twzrd-agent-intel (Python/MCP)](https://github.com/twzrd-sol/wzrd-final/tree/main/packages/twzrd-agent-intel)
129
- - [Agent discovery](https://twzrd.xyz/llms.txt)
235
+ - [API docs / llms.txt](https://intel.twzrd.xyz/llms.txt)
236
+ - [x402 gate (standalone firewall)](https://www.npmjs.com/package/twzrd-x402-gate)
237
+ - [GOAT plugin](https://www.npmjs.com/package/@wzrd_sol/goat-plugin)
238
+ - [TWZRD trust quickstart](https://intel.twzrd.xyz/docs/QUICKSTART.md)
130
239
 
131
240
  ## License
132
241
 
133
- MIT
242
+ MIT
@@ -62,9 +62,9 @@ export const intelPreflightAction = {
62
62
  handler: async (runtime, message, _state, _opt, callback) => {
63
63
  const content = (message.content ?? {});
64
64
  const input = parsePreflightInput(content);
65
- if (!input.seller_wallet && !input.resource_name && !input.resource_url && !input.agent_intent) {
65
+ if (!input.seller_wallet && !input.resource_name && !input.resource_url) {
66
66
  await callback?.({
67
- text: 'Provide seller_wallet, resource_name, resource_url, or agent_intent for preflight. ' +
67
+ text: 'Provide seller_wallet, resource_name, or resource_url for preflight. ' +
68
68
  'Example: "Preflight seller JUP6Lkb... at 0.25 USDC"',
69
69
  });
70
70
  return { success: false, error: 'Missing preflight input' };
@@ -1,7 +1,7 @@
1
1
  /**
2
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).
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;
@@ -5,7 +5,7 @@ export const intelTrustAction = {
5
5
  name: 'WZRD_INTEL_TRUST',
6
6
  similes: ['WZRD_TRUST_RECEIPT', 'INTEL_TRUST', 'GET_TRUST_RECEIPT'],
7
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. ' +
8
+ 'Runs free preflight + merchant_card wash check first; aborts on decision=block or wash_flagged. ' +
9
9
  'Requires an x402-capable fetchImpl (setPayingFetch or host service). ' +
10
10
  'Surfaces payment requirements if no payer is configured.',
11
11
  examples: [
@@ -24,24 +24,32 @@ export const intelTrustAction = {
24
24
  }
25
25
  const apiBase = getIntelBase(runtime);
26
26
  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
27
+ // preflight-before-pay + wash refuse: FREE ReadinessCard + free merchant_card.
28
+ // Abort on decision=block or wash_flagged before any payment. failOpen=false so
29
29
  // 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.
30
+ // plugin must demonstrate the safe posture, not bypass it. Free reads only.
32
31
  try {
33
- const gate = await preSpendGate({ seller_wallet: pubkey }, { apiBase, failOpen: false, fetchImpl: baseFetchImpl });
32
+ const gate = await preSpendGate({ seller_wallet: pubkey }, { apiBase, failOpen: false, refuseWashFlagged: true, fetchImpl: baseFetchImpl });
34
33
  if (!gate.allow) {
34
+ const washLine = gate.washFlagged === true
35
+ ? `Wash flagged: yes (merchant_card refuse default)\n`
36
+ : '';
35
37
  await callback?.({
36
38
  text: `Preflight blocked the trust purchase for ${pubkey}.\n` +
37
39
  `Decision: ${gate.decision}${gate.trustScore != null ? `, trust_score=${gate.trustScore}` : ''}\n` +
40
+ washLine +
38
41
  `Reason: ${gate.reason}\n` +
39
42
  `No payment was sent.`,
40
43
  });
41
44
  return {
42
45
  success: false,
43
- error: 'preflight_block',
44
- data: { decision: gate.decision, trustScore: gate.trustScore, reason: gate.reason },
46
+ error: gate.washFlagged === true ? 'wash_flagged' : 'preflight_block',
47
+ data: {
48
+ decision: gate.decision,
49
+ trustScore: gate.trustScore,
50
+ reason: gate.reason,
51
+ washFlagged: gate.washFlagged ?? null,
52
+ },
45
53
  };
46
54
  }
47
55
  }
@@ -57,14 +65,21 @@ export const intelTrustAction = {
57
65
  return fetchIntelTrust(pubkey, { apiBase, fetchImpl: abortingFetch });
58
66
  });
59
67
  const receipt = res.twzrd_receipt;
60
- const text = `Trust payload for ${pubkey}\n` +
61
- `Score: ${res.trust?.score ?? 'n/a'}\n` +
62
- `Paid: ${res.paid ? 'yes' : 'no'}\n` +
63
- (res.tx ? `Settlement tx: ${res.tx}\n` : '') +
64
- (receipt
65
- ? `Receipt v${receipt.version}, leaf: ${receipt.leaf}\n` +
66
- `Use WZRD_VERIFY_RECEIPT to verify offline.`
67
- : 'No twzrd_receipt in response.');
68
+ const vc = res.reputation_credential?.credentialSubject;
69
+ const lines = [
70
+ `Trust payload for ${pubkey}`,
71
+ `Score: ${res.trust?.score ?? 'n/a'} Paid: ${res.paid ? 'yes' : 'no'}`,
72
+ ];
73
+ const settleTx = res.tx ?? res.tx_pending;
74
+ if (settleTx)
75
+ lines.push(`Settlement tx${res.tx ? '' : ' (pending)'}: ${settleTx}`);
76
+ if (vc) {
77
+ lines.push(`Reputation credential (ERC-8004 AgentReputationCredential):`, ` effectiveTrustScore: ${vc.effectiveTrustScore ?? 'n/a'}`, ` trustScore: ${vc.trustScore ?? 'n/a'} washFactor: ${vc.washFactor ?? 'n/a'}`, ` distinctCounterparties: ${vc.distinctCounterparties ?? 'n/a'}`, ` corpusScope: ${vc.corpusScope ?? 'n/a'}`, ` version: ${vc.trustScoreVersion ?? 'n/a'}`, `Routing gate: effectiveTrustScore < 30 → block, 30-60 → warn, > 60 → allow`);
78
+ }
79
+ lines.push(receipt
80
+ ? `Receipt v${receipt.version}, leaf: ${receipt.leaf}\nUse WZRD_VERIFY_RECEIPT to verify offline.`
81
+ : 'No twzrd_receipt in response.');
82
+ const text = lines.join('\n');
68
83
  await callback?.({ text });
69
84
  return { success: true, data: res };
70
85
  }
@@ -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
+ };
package/dist/client.d.ts CHANGED
@@ -75,7 +75,7 @@ export declare class WzrdClient {
75
75
  quality_score?: number;
76
76
  latency_ms?: number;
77
77
  }): Promise<ReportResult>;
78
- /** Check pending + total rewards (flattens nested /v1/agent/earned response) */
78
+ /** Check pending + total rewards (reads flat /v1/agent/earned response) */
79
79
  getRewards(): Promise<RewardsBalance>;
80
80
  /** Gasless CCM claim via server relay */
81
81
  claimRelay(): Promise<ClaimResult>;
package/dist/client.js CHANGED
@@ -87,19 +87,17 @@ export class WzrdClient {
87
87
  }
88
88
  return res.json();
89
89
  }
90
- /** Check pending + total rewards (flattens nested /v1/agent/earned response) */
90
+ /** Check pending + total rewards (reads flat /v1/agent/earned response) */
91
91
  async getRewards() {
92
92
  const res = await this.authedFetch('/v1/agent/earned');
93
93
  if (!res.ok)
94
94
  throw new Error(`Rewards check failed: ${res.status}`);
95
95
  const data = await res.json();
96
- const economy = data.economy;
97
- const routing = data.routing;
98
96
  return {
99
- pending_ccm: Number(economy?.pending_ccm ?? 0),
100
- total_rewarded_ccm: Number(economy?.earned_ccm ?? 0),
101
- rank: null, // rank not in this endpoint
102
- contribution_count: Number(routing?.lifetime_contributions ?? 0),
97
+ pending_ccm: Number(data.pending_ccm ?? 0),
98
+ total_rewarded_ccm: Number(data.total_earned_ccm ?? 0),
99
+ rank: data.rank == null ? null : Number(data.rank),
100
+ contribution_count: Number(data.lifetime_contributions ?? 0),
103
101
  };
104
102
  }
105
103
  /** Gasless CCM claim via server relay */
package/dist/index.d.ts CHANGED
@@ -2,8 +2,9 @@
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
5
+ * WZRD_INTEL_PREFLIGHT → WZRD_MERCHANT_CARD → WZRD_INTEL_TRUST → WZRD_VERIFY_RECEIPT
6
6
  * Paid intel requires caller-supplied x402 fetch via setPayingFetch().
7
+ * Default: preSpendGate refuses wash_flagged pay_to (free merchant_card).
7
8
  *
8
9
  * Earn lane (default https://api.twzrd.xyz):
9
10
  * WZRD_INFER → WZRD_REPORT → WZRD_EARN → WZRD_CLAIM / WZRD_REWARDS
@@ -20,14 +21,15 @@ import { earnAction } from './actions/earn.js';
20
21
  import { claimAction } from './actions/claim.js';
21
22
  import { rewardsAction } from './actions/rewards.js';
22
23
  import { intelPreflightAction } from './actions/intel-preflight.js';
24
+ import { merchantCardAction } from './actions/merchant-card.js';
23
25
  import { intelTrustAction } from './actions/intel-trust.js';
24
26
  import { verifyReceiptAction } from './actions/verify-receipt.js';
25
27
  export declare const wzrdPlugin: Plugin;
26
28
  export default wzrdPlugin;
27
- export { intelPreflightAction, intelTrustAction, verifyReceiptAction, earnAction, inferAction, reportAction, claimAction, rewardsAction, };
29
+ export { intelPreflightAction, merchantCardAction, intelTrustAction, verifyReceiptAction, earnAction, inferAction, reportAction, claimAction, rewardsAction, };
28
30
  export { getWzrdClient, clearClientCache, getIntelApiBase, getIntelClient } from './client-factory.js';
29
31
  export { setPayingFetch, clearPayingFetch, resolvePayingFetch } from './paying-fetch.js';
30
32
  export { WzrdClient } from './client.js';
31
33
  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';
34
+ export { IntelPaymentRequiredError, intelPreflight, fetchIntelTrust, fetchMerchantCard, verifyReceipt, preSpendGate, intelTrustUrl, TRUSTED_RECEIPT_PUBKEY, INTEL_TRUST_PRICE_USDC, } from '@wzrd_sol/sdk';
35
+ export type { ReadinessCard, PreflightInput, PreflightResponse, MerchantCard, TwzrdReceipt, IntelTrustResponse, VerifyReceiptResult, X402PaymentRequired, } from '@wzrd_sol/sdk';
package/dist/index.js CHANGED
@@ -4,15 +4,17 @@ 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 + merchant_card wash refuse (default), ' +
13
+ 'x402-paid trust receipts (V5/V6), offline verification on intel.twzrd.xyz. ' +
14
+ 'Also ships the legacy earn loop (infer/report/claim) on api.twzrd.xyz.',
14
15
  actions: [
15
16
  intelPreflightAction,
17
+ merchantCardAction,
16
18
  intelTrustAction,
17
19
  verifyReceiptAction,
18
20
  earnAction,
@@ -23,8 +25,8 @@ export const wzrdPlugin = {
23
25
  ],
24
26
  };
25
27
  export default wzrdPlugin;
26
- export { intelPreflightAction, intelTrustAction, verifyReceiptAction, earnAction, inferAction, reportAction, claimAction, rewardsAction, };
28
+ export { intelPreflightAction, merchantCardAction, intelTrustAction, verifyReceiptAction, earnAction, inferAction, reportAction, claimAction, rewardsAction, };
27
29
  export { getWzrdClient, clearClientCache, getIntelApiBase, getIntelClient } from './client-factory.js';
28
30
  export { setPayingFetch, clearPayingFetch, resolvePayingFetch } from './paying-fetch.js';
29
31
  export { WzrdClient } from './client.js';
30
- export { IntelPaymentRequiredError, intelPreflight, fetchIntelTrust, verifyReceipt, preSpendGate, intelTrustUrl, TRUSTED_RECEIPT_PUBKEY, INTEL_TRUST_PRICE_USDC, } from '@wzrd_sol/sdk';
32
+ export { IntelPaymentRequiredError, intelPreflight, fetchIntelTrust, fetchMerchantCard, verifyReceipt, preSpendGate, intelTrustUrl, TRUSTED_RECEIPT_PUBKEY, INTEL_TRUST_PRICE_USDC, } from '@wzrd_sol/sdk';
@@ -41,9 +41,10 @@ export function parseReceipt(content) {
41
41
  }
42
42
  return null;
43
43
  }
44
+ const SOLANA_PUBKEY_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
44
45
  export function extractPubkey(content) {
45
46
  const direct = str(content.pubkey ?? content.seller_wallet ?? content.wallet);
46
- if (direct)
47
+ if (direct && SOLANA_PUBKEY_RE.test(direct))
47
48
  return direct;
48
49
  const text = str(content.text);
49
50
  if (!text)
@@ -51,7 +52,7 @@ export function extractPubkey(content) {
51
52
  const fromJson = tryParseJson(text);
52
53
  if (fromJson) {
53
54
  const w = str(fromJson.pubkey ?? fromJson.seller_wallet ?? fromJson.wallet);
54
- if (w)
55
+ if (w && SOLANA_PUBKEY_RE.test(w))
55
56
  return w;
56
57
  }
57
58
  return extractWallet(text);
@@ -71,7 +72,10 @@ export function formatPaymentRequired(err, apiBase, pubkey) {
71
72
  `No paying fetch configured. Wire one before runtime creation:\n` +
72
73
  ` import { setPayingFetch } from '@wzrd_sol/eliza-plugin';\n` +
73
74
  ` setPayingFetch(myAgentcashFetch);\n\n` +
74
- `Or pay out of band:\n` +
75
+ `Pay out of band only with an x402 client that preserves the sponsored fee-payer slot.\n` +
76
+ `Caveat: npx agentcash@latest fetch is not currently a green TWZRD repro; ` +
77
+ `it failed closed with payment_invalid / fee_payer_slot_already_signed on 2026-06-23.\n` +
78
+ `Known-bad compatibility command:\n` +
75
79
  ` npx agentcash@latest fetch ${url}`);
76
80
  }
77
81
  function str(v) {
@@ -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.1",
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.3.3",
4
+ "description": "WZRD Agent Intel for ElizaOS — preflight ReadinessCards, free merchant_card wash refuse default, x402-paid signed trust receipts (V6 reputation leaf), offline verification on intel.twzrd.xyz. Also ships the legacy earn loop.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -19,7 +19,7 @@
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
24
  "tweetnacl": "^1.0.3"
25
25
  },