diff --git a/AGENTS.md b/AGENTS.md
index e28f925..2c2c98f 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -143,9 +143,18 @@ session with **no other memory of this project**. So:
~0 even when cross-confirmed. **Ring analysis** — `useTradeRings` does a
**2-hop** query of the partners' own attestations and measures **closedness**
(share of possible partner↔partner trades); `≥3` partners with `≥0.5`
- closedness flags a closed cluster. ⚠️ **PoW (NIP-13) is the remaining lever**
- but requires **mining at publish** (and a read-side verifier) — a verifier
- alone does nothing because no events carry a `nonce` yet. Deferred.
+ closedness flags a closed cluster.
+ - **NIP-13 proof of work (2026-10-01):** `src/lib/pow.ts` (`minePow` /
+ `verifyPow` / `countLeadingZeroBits`). ⚠️ **PoW pays no one** — it is a free
+ **CPU** tax, not a fee; don't describe it as a payment. `useNostrPublish`
+ accepts `pow?: number` and **mines the nonce on the UNSIGNED event before
+ signing** (the id is signature-independent, so the signer is still prompted
+ once). `CreateListingPage` sends **16 bits** on every listing (~80 ms) and
+ **20 bits** when a **newcomer picks work instead of the 1,000-sat listing
+ fee** (`SpamFeePayment.onPowInstead` → the free alternative). `parseMarketplaceItem`
+ exposes `powDifficulty` and `MarketplaceItemCard` shows a **⚡ PoW badge** at
+ ≥16. It raises cost, it doesn't prove humanity; keep targets low (mining runs
+ on the main thread with periodic yields).
- **Cashu escrow** (marketplace): time-locked **P2PK** (lock to seller + buyer
refund key + locktime) — see **`ESCROW.md`** and `src/lib/cashuEscrow.ts`
(unit-tested). Protocol: `cashu_token` on the `31872`; each user advertises a
diff --git a/src/components/MarketplaceItemCard.tsx b/src/components/MarketplaceItemCard.tsx
index e08e2a4..9538f44 100644
--- a/src/components/MarketplaceItemCard.tsx
+++ b/src/components/MarketplaceItemCard.tsx
@@ -343,6 +343,15 @@ export function MarketplaceItemCard({ item, compact = false }: MarketplaceItemCa
: '📍📦 Pickup or ship'}
)}
+ {typeof item.powDifficulty === 'number' && item.powDifficulty >= 16 && (
+
+ ⚡ PoW {item.powDifficulty}
+
+ )}
{sellerRep && sellerRep.verified > 0 && (
diff --git a/src/components/SpamFeePayment.tsx b/src/components/SpamFeePayment.tsx
index 9e1767e..075c6da 100644
--- a/src/components/SpamFeePayment.tsx
+++ b/src/components/SpamFeePayment.tsx
@@ -14,6 +14,8 @@ interface SpamFeePaymentProps {
feeRecipient: string;
feeRecipientName: string;
onPaymentSuccess: () => void;
+ /** Offered as a FREE alternative to the sats fee: mine NIP-13 proof of work. */
+ onPowInstead?: () => void;
onSkip?: () => void;
}
@@ -23,6 +25,7 @@ export function SpamFeePayment({
feeRecipient,
feeRecipientName,
onPaymentSuccess,
+ onPowInstead,
}: SpamFeePaymentProps) {
const { toast } = useToast();
const { webln, activeNWC } = useWallet();
@@ -210,15 +213,33 @@ export function SpamFeePayment({