Built on the Attestations NIP (31871); a listing is the Assertion Event: - Seller 'Mark as sold' now opens a dialog (buyer npub + self-reported method + optional amount) that marks the listing sold AND publishes a trade attestation - Buyer sees 'Confirm this trade' on the listing and publishes the mirror attestation -> mutual pair = a verified trade - useTradeReputation aggregates sales/purchases/verified + counterparties - Profile 'Trades' card; seller 'N verified trades' badge on listing cards - NIP.md documents kind 31871 usage + our p/method/amount extensions Payment method is self-reported metadata, never proof of payment.
58 lines
2 KiB
TypeScript
58 lines
2 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import type { NostrEvent } from '@nostrify/nostrify';
|
|
import { parseListingCoord, isTradeAttestation, TRADE_ATTESTATION_KIND } from './useTradeAttestations';
|
|
|
|
function ev(partial: Partial<NostrEvent> & Pick<NostrEvent, 'kind' | 'pubkey' | 'id'>): NostrEvent {
|
|
return { content: '', created_at: 0, sig: '', tags: [], ...partial } as NostrEvent;
|
|
}
|
|
|
|
describe('parseListingCoord', () => {
|
|
it('parses a 30402 coordinate', () => {
|
|
expect(parseListingCoord('30402:abc123:my-listing')).toEqual({
|
|
kind: 30402,
|
|
pubkey: 'abc123',
|
|
identifier: 'my-listing',
|
|
});
|
|
});
|
|
|
|
it('keeps colons that are part of the identifier', () => {
|
|
expect(parseListingCoord('30402:abc123:slug:part2')?.identifier).toBe('slug:part2');
|
|
});
|
|
|
|
it('returns null for missing or malformed coords', () => {
|
|
expect(parseListingCoord(undefined)).toBeNull();
|
|
expect(parseListingCoord('nope')).toBeNull();
|
|
expect(parseListingCoord('30402:onlypubkey')).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('isTradeAttestation', () => {
|
|
it('accepts a 31871 attestation of a 30402 listing with a counterparty', () => {
|
|
const e = ev({
|
|
kind: TRADE_ATTESTATION_KIND,
|
|
pubkey: 'seller',
|
|
id: 'a1',
|
|
tags: [['a', '30402:seller:deck'], ['p', 'buyer'], ['s', 'valid']],
|
|
});
|
|
expect(isTradeAttestation(e)).toBe(true);
|
|
});
|
|
|
|
it('rejects an attestation without a counterparty', () => {
|
|
const e = ev({
|
|
kind: TRADE_ATTESTATION_KIND,
|
|
pubkey: 'x',
|
|
id: 'a2',
|
|
tags: [['a', '30402:x:y'], ['s', 'valid']],
|
|
});
|
|
expect(isTradeAttestation(e)).toBe(false);
|
|
});
|
|
|
|
it('rejects non-listing assertions and other kinds', () => {
|
|
expect(
|
|
isTradeAttestation(ev({ kind: TRADE_ATTESTATION_KIND, pubkey: 'x', id: 'a3', tags: [['a', '35000:x:y'], ['p', 'z']] })),
|
|
).toBe(false);
|
|
expect(
|
|
isTradeAttestation(ev({ kind: 1, pubkey: 'x', id: 'a4', tags: [['a', '30402:x:y'], ['p', 'z']] })),
|
|
).toBe(false);
|
|
});
|
|
});
|