capacity-attest 0.4.0 → 0.6.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.
@@ -0,0 +1,80 @@
1
+ import { type DeliveryClaim } from "./schema.js";
2
+ import { type CompletenessReport } from "./completeness.js";
3
+ /**
4
+ * An untrusted place claims about a seller can be discovered: the local
5
+ * ledger, a shared file, an EAS query on Base, another installation's public
6
+ * endpoint, an IPFS/git convention, etc. `fetchForSeller` may return anything,
7
+ * including forged or junk claims; discoverDeliveryHistory re-verifies all of
8
+ * them, so a source is never trusted, only read.
9
+ */
10
+ export interface ClaimSource {
11
+ /** Human label for per-source accounting in the result. */
12
+ name: string;
13
+ /** Return whatever this source believes are claims about sellerAddress. Untrusted. */
14
+ fetchForSeller(sellerAddress: string): Promise<DeliveryClaim[]>;
15
+ }
16
+ /** Per-source accounting: what a source returned, and how much survived verification. */
17
+ export interface SourceReport {
18
+ name: string;
19
+ /** How many entries the source returned (before any cap). */
20
+ fetched: number;
21
+ /** How many verified, concerned this seller, AND were not already contributed by an earlier source. */
22
+ accepted: number;
23
+ /** How many FAILED verifyClaim (forged/tampered/junk). Cryptographic failures only. */
24
+ rejected: number;
25
+ /** How many verified fine but were about a DIFFERENT seller (honest-but-off-topic, not a forgery). */
26
+ wrongSeller: number;
27
+ /** How many verified but were duplicates of a claim already seen (same claimId). */
28
+ duplicates: number;
29
+ /** Set when the source returned more than the per-source cap; only the first cap entries were examined. */
30
+ truncated?: boolean;
31
+ /** Set only when fetchForSeller threw OR resolved to a non-array; the source is skipped, others still run. */
32
+ error?: string;
33
+ }
34
+ /** Optional per-call limits, mainly so tests can exercise the caps cheaply; production uses the defaults above. */
35
+ export interface DiscoverOptions {
36
+ maxClaimsPerSource?: number;
37
+ maxTotalClaims?: number;
38
+ }
39
+ export interface AggregatedHistory {
40
+ sellerAddress: string;
41
+ /** Distinct, verified claims for this seller across all sources, oldest first. */
42
+ count: number;
43
+ claims: DeliveryClaim[];
44
+ /** Per-source contribution accounting. */
45
+ sources: SourceReport[];
46
+ /** Completeness analysis over the aggregated set (same meaning + limits as D-006). */
47
+ completeness: CompletenessReport;
48
+ /** Fixed, factual note about what aggregation does and does not guarantee. */
49
+ note: string;
50
+ }
51
+ /**
52
+ * Trustless cross-installation aggregation. Reads a seller's claims from every
53
+ * source, de-duplicates by claimId, re-verifies each one (dropping anything
54
+ * that fails), and runs completeness over the survivors. No source is trusted;
55
+ * a source that throws is recorded and skipped, never fatal.
56
+ *
57
+ * Order note: sources are processed in the order given, purely so per-source
58
+ * `accepted`/`duplicates` accounting is deterministic (the first source to
59
+ * carry a given claimId gets the `accepted` credit; later ones counting it as
60
+ * a duplicate). The final `claims` array is sorted by timestamp regardless of
61
+ * source order, so the aggregate itself does not depend on which source is
62
+ * listed first.
63
+ */
64
+ export declare function discoverDeliveryHistory(sellerAddress: string, sources: ClaimSource[], opts?: DiscoverOptions): Promise<AggregatedHistory>;
65
+ /**
66
+ * A source backed by THIS installation's local ledger. This is the one source
67
+ * that is already trusted in the sense that its own read path re-verifies, but
68
+ * discoverDeliveryHistory re-verifies it anyway (harmless, keeps the trust
69
+ * model uniform: no source is special).
70
+ */
71
+ export declare function localLedgerSource(name?: string): ClaimSource;
72
+ /**
73
+ * A source over a fixed, in-memory list of claims. Used to simulate a
74
+ * host-independent substrate (a shared file, an EAS query result, another
75
+ * installation's export) in tests and the discovery fixture, without a network
76
+ * or a chain. Deliberately does NO verification itself, so the aggregation's
77
+ * own verification is what the tests actually exercise.
78
+ */
79
+ export declare function staticSource(name: string, claims: DeliveryClaim[]): ClaimSource;
80
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAqCA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAGtE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AASjF;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;CACjE;AAED,yFAAyF;AACzF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,uGAAuG;IACvG,QAAQ,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,QAAQ,EAAE,MAAM,CAAC;IACjB,sGAAsG;IACtG,WAAW,EAAE,MAAM,CAAC;IACpB,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,2GAA2G;IAC3G,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,8GAA8G;IAC9G,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,mHAAmH;AACnH,MAAM,WAAW,eAAe;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,0CAA0C;IAC1C,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,sFAAsF;IACtF,YAAY,EAAE,kBAAkB,CAAC;IACjC,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;CACd;AAoBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAC3C,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,WAAW,EAAE,EACtB,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAiG5B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,SAAiB,GAAG,WAAW,CAKpE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,WAAW,CAK/E"}
@@ -0,0 +1,199 @@
1
+ // discovery.ts — cross-installation claim discovery (D-005).
2
+ //
3
+ // THE PROBLEM (DECISIONS.md D-005): a buyer's claim about a seller lives only
4
+ // in that buyer's local ledger. A different buyer, on a separate installation,
5
+ // cannot see it via get_delivery_history before deciding to pay the same
6
+ // seller. get_delivery_history is, by construction, local-only.
7
+ //
8
+ // THE INSIGHT that makes findability solvable WITHOUT a trusted index: our
9
+ // claims are already self-verifying (claimId is a content hash, signature
10
+ // recovers to buyerAddress). So discovery does not need anyone to be trusted.
11
+ // Claims can be published anywhere, and whoever discovers them re-verifies each
12
+ // one locally. A source that injects a forged claim is caught by verifyClaim;
13
+ // a source that omits claims is the D-006 completeness problem, unchanged and
14
+ // carried over here (analyzeCompleteness still runs on the aggregate). So
15
+ // findability and verification compose cleanly: gather from anywhere untrusted,
16
+ // verify everything locally.
17
+ //
18
+ // WHAT THIS MODULE IS: the trustless client-side aggregation. Given several
19
+ // independent SOURCES (the local ledger, and any host-independent substrate a
20
+ // buyer chooses to also read), it fetches claims for a seller from each,
21
+ // de-duplicates by claimId, RE-VERIFIES every single one regardless of which
22
+ // source produced it, and runs the completeness analysis over the surviving
23
+ // set. The result carries per-source accounting so the caller can see what
24
+ // each source contributed and what was rejected.
25
+ //
26
+ // WHAT THIS MODULE IS NOT, stated so it is never oversold:
27
+ // - It does not run, host, or endorse any index. A `ClaimSource` is an
28
+ // UNTRUSTED input; the trust comes entirely from re-verifying each claim.
29
+ // - It does not solve completeness. If a source silently omits claims, this
30
+ // cannot invent them; analyzeCompleteness carries over the same honest
31
+ // detection/limits from D-006 (catches a hidden middle claim in a chain
32
+ // it can see, not a hidden tail or a hidden whole buyer).
33
+ // - The production substrate (EAS on Base, ERC-8004) is deliberately NOT
34
+ // wired here. That needs gas, a live chain, and a real integrator; see
35
+ // DECISIONS.md D-005/D-012. This module is the substrate-agnostic seam
36
+ // plus a reference in-memory/static source for simulation and tests.
37
+ import { DeliveryClaimSchema } from "./schema.js";
38
+ import { verifyClaim } from "./signing.js";
39
+ import { claimsForSeller } from "./ledger.js";
40
+ import { analyzeCompleteness } from "./completeness.js";
41
+ // Bound the work a single untrusted source can force. Defense against VOLUME
42
+ // (a source returning millions of entries, or an attacker generating millions
43
+ // of genuinely-valid self-signed claims), not against Sybil (see the note).
44
+ // Overridable per call via DiscoverOptions.
45
+ const MAX_CLAIMS_PER_SOURCE = 10_000;
46
+ const MAX_TOTAL_CLAIMS = 50_000;
47
+ const DISCOVERY_NOTE = "Aggregated from independent, UNTRUSTED sources. Every claim shown was re-verified locally (claimId recomputed and " +
48
+ "signature recovered to buyerAddress), so a source cannot inject a forged claim. What verification proves is narrow: " +
49
+ "it proves AUTHORSHIP of the content, NOT that a real payment or delivery happened (settlementRef is not checked " +
50
+ "on-chain here) and NOT that buyers are distinct. So a single keypair can still flood valid positive claims to " +
51
+ "inflate a seller, or valid negatives to grief one; volume and Sybil are not addressed by aggregation. This solves " +
52
+ "findability across installations, NOT completeness: a source can still omit claims, and no aggregation can invent " +
53
+ "what no source reveals. The completeness field carries the same D-006 detection and limits over the aggregate. Add " +
54
+ "more independent sources to raise the cost of a coordinated omission; it never reaches a proof. See DECISIONS.md D-005.";
55
+ function lower(s) {
56
+ return s.toLowerCase();
57
+ }
58
+ function timestampMs(claim) {
59
+ return Date.parse(claim.timestamp);
60
+ }
61
+ /**
62
+ * Trustless cross-installation aggregation. Reads a seller's claims from every
63
+ * source, de-duplicates by claimId, re-verifies each one (dropping anything
64
+ * that fails), and runs completeness over the survivors. No source is trusted;
65
+ * a source that throws is recorded and skipped, never fatal.
66
+ *
67
+ * Order note: sources are processed in the order given, purely so per-source
68
+ * `accepted`/`duplicates` accounting is deterministic (the first source to
69
+ * carry a given claimId gets the `accepted` credit; later ones counting it as
70
+ * a duplicate). The final `claims` array is sorted by timestamp regardless of
71
+ * source order, so the aggregate itself does not depend on which source is
72
+ * listed first.
73
+ */
74
+ export async function discoverDeliveryHistory(sellerAddress, sources, opts = {}) {
75
+ const maxPerSource = opts.maxClaimsPerSource ?? MAX_CLAIMS_PER_SOURCE;
76
+ const maxTotal = opts.maxTotalClaims ?? MAX_TOTAL_CLAIMS;
77
+ const byId = new Map();
78
+ const sourceReports = [];
79
+ for (const source of sources) {
80
+ let fetched;
81
+ try {
82
+ fetched = await source.fetchForSeller(sellerAddress);
83
+ }
84
+ catch (e) {
85
+ sourceReports.push({ name: source.name, fetched: 0, accepted: 0, rejected: 0, wrongSeller: 0, duplicates: 0, error: e.message });
86
+ continue;
87
+ }
88
+ // An untrusted source may RESOLVE (not reject) to anything, including a
89
+ // non-array: malformed JSON from a real HTTP/EAS source, or a hostile one
90
+ // trying to abort the whole aggregation. Treat that as a per-source error
91
+ // and keep going. Without this guard the `for...of` below throws
92
+ // "not iterable", rejects discoverDeliveryHistory entirely, and censors
93
+ // every other source including the local ledger — defeating the very
94
+ // fault-isolation this function promises.
95
+ if (!Array.isArray(fetched)) {
96
+ sourceReports.push({ name: source.name, fetched: 0, accepted: 0, rejected: 0, wrongSeller: 0, duplicates: 0, error: "source did not return an array" });
97
+ continue;
98
+ }
99
+ let accepted = 0;
100
+ let rejected = 0;
101
+ let wrongSeller = 0;
102
+ let duplicates = 0;
103
+ // Bound the work this source can force: examine at most maxPerSource
104
+ // entries, and stop growing the aggregate past maxTotal. A source that
105
+ // returns more is marked `truncated` rather than allowed to exhaust
106
+ // CPU/memory on untrusted input.
107
+ const limit = Math.min(fetched.length, maxPerSource);
108
+ const truncated = fetched.length > maxPerSource;
109
+ for (let i = 0; i < limit; i++) {
110
+ if (byId.size >= maxTotal)
111
+ break;
112
+ const claim = fetched[i];
113
+ // Re-verify EVERY claim, from EVERY source, no exceptions: this is the
114
+ // entire trust model. A source is just bytes until verifyClaim passes.
115
+ let verdict;
116
+ try {
117
+ verdict = verifyClaim(claim);
118
+ }
119
+ catch {
120
+ // computeClaimId can throw on pathological content (e.g. promisedSpec
121
+ // past MAX_DEPTH); treat exactly like a failed verification.
122
+ rejected++;
123
+ continue;
124
+ }
125
+ if (!verdict.ok) {
126
+ rejected++;
127
+ continue;
128
+ }
129
+ // Valid, but about a DIFFERENT seller: honest-but-off-topic, tracked
130
+ // separately from cryptographic rejections so an honest source that
131
+ // simply returns other sellers' claims is not mislabeled as feeding
132
+ // forgeries (case-insensitive, matching ledger semantics).
133
+ if (lower(claim.sellerAddress) !== lower(sellerAddress)) {
134
+ wrongSeller++;
135
+ continue;
136
+ }
137
+ const key = lower(claim.claimId);
138
+ if (byId.has(key)) {
139
+ duplicates++;
140
+ continue;
141
+ }
142
+ // Store the schema-parsed form so no unverified, attacker-attached
143
+ // top-level key rides into the result. verifyClaim already proved the
144
+ // content hashes to claimId; parsing strips anything outside the signed
145
+ // shape. It cannot fail here (the claim already passed verifyClaim,
146
+ // whose computeClaimId parses the same content), but guard anyway since
147
+ // the input is untrusted.
148
+ let parsed;
149
+ try {
150
+ parsed = DeliveryClaimSchema.parse(claim);
151
+ }
152
+ catch {
153
+ rejected++;
154
+ continue;
155
+ }
156
+ byId.set(key, parsed);
157
+ accepted++;
158
+ }
159
+ const report = { name: source.name, fetched: fetched.length, accepted, rejected, wrongSeller, duplicates };
160
+ if (truncated)
161
+ report.truncated = true;
162
+ sourceReports.push(report);
163
+ }
164
+ const claims = [...byId.values()].sort((a, b) => timestampMs(a) - timestampMs(b));
165
+ return {
166
+ sellerAddress,
167
+ count: claims.length,
168
+ claims,
169
+ sources: sourceReports,
170
+ completeness: analyzeCompleteness(claims),
171
+ note: DISCOVERY_NOTE,
172
+ };
173
+ }
174
+ /**
175
+ * A source backed by THIS installation's local ledger. This is the one source
176
+ * that is already trusted in the sense that its own read path re-verifies, but
177
+ * discoverDeliveryHistory re-verifies it anyway (harmless, keeps the trust
178
+ * model uniform: no source is special).
179
+ */
180
+ export function localLedgerSource(name = "local-ledger") {
181
+ return {
182
+ name,
183
+ fetchForSeller: (sellerAddress) => claimsForSeller(sellerAddress),
184
+ };
185
+ }
186
+ /**
187
+ * A source over a fixed, in-memory list of claims. Used to simulate a
188
+ * host-independent substrate (a shared file, an EAS query result, another
189
+ * installation's export) in tests and the discovery fixture, without a network
190
+ * or a chain. Deliberately does NO verification itself, so the aggregation's
191
+ * own verification is what the tests actually exercise.
192
+ */
193
+ export function staticSource(name, claims) {
194
+ return {
195
+ name,
196
+ fetchForSeller: async (sellerAddress) => claims.filter((c) => lower(c.sellerAddress) === lower(sellerAddress)),
197
+ };
198
+ }
199
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
package/dist/eas.d.ts ADDED
@@ -0,0 +1,81 @@
1
+ import { ethers } from "ethers";
2
+ import { type DeliveryClaim } from "./schema.js";
3
+ import { verifyClaim } from "./signing.js";
4
+ import type { ClaimSource } from "./discovery.js";
5
+ export declare const EAS_ADDRESS = "0x4200000000000000000000000000000000000021";
6
+ export declare const SCHEMA_REGISTRY_ADDRESS = "0x4200000000000000000000000000000000000020";
7
+ export declare const EAS_EXPLORER: {
8
+ readonly 8453: "https://base.easscan.org";
9
+ readonly 84532: "https://base-sepolia.easscan.org";
10
+ };
11
+ export declare const SCHEMA_STRING = "bytes32 claimId,string claim";
12
+ /** Deterministic schema UID: keccak256(abi.encodePacked(schema, resolver, revocable)). */
13
+ export declare function computeSchemaUID(schema?: string, resolver?: string, revocable?: boolean): string;
14
+ export declare const SCHEMA_UID: string;
15
+ /** ABI-encode a claim into EAS attestation data for SCHEMA_STRING. */
16
+ export declare function encodeClaimData(claim: DeliveryClaim): string;
17
+ /**
18
+ * Decode EAS attestation data back into a claim. Returns null if the data does
19
+ * not decode or the JSON does not parse into our claim shape. NEVER trusts the
20
+ * result: the caller (easSource / discoverDeliveryHistory) re-verifies with
21
+ * verifyClaim. The on-chain bytes32 claimId is cross-checked against the JSON's
22
+ * own claimId, so a mismatch is dropped here as malformed.
23
+ */
24
+ export declare function decodeClaimData(data: string): DeliveryClaim | null;
25
+ /**
26
+ * Register our schema if it does not already exist on this chain. The schema
27
+ * UID is deterministic, so a duplicate register() reverts with AlreadyExists;
28
+ * we check first via getSchema and only register when absent. Requires a
29
+ * funded signer. Returns the schema UID.
30
+ */
31
+ export declare function ensureSchema(signer: ethers.Signer): Promise<string>;
32
+ export interface PublishResult {
33
+ uid: string;
34
+ txHash: string;
35
+ recipient: string;
36
+ }
37
+ /**
38
+ * Publish one claim to EAS as an attestation with recipient = sellerAddress, so
39
+ * it is discoverable by that seller. `signer` only pays gas and writes the
40
+ * transaction; it does not need to be, and normally is not, the buyer. The
41
+ * buyer identity lives entirely inside `claim` (buyerAddress, checked by
42
+ * verifyClaim against the signature over claimId): nothing on the read path
43
+ * (easSource, discoverDeliveryHistory) ever looks at who published the
44
+ * attestation, only at what the claim itself proves. Requires a funded signer.
45
+ * Returns the new attestation UID and tx hash.
46
+ */
47
+ export declare function publishClaim(signer: ethers.Signer, claim: DeliveryClaim): Promise<PublishResult>;
48
+ /**
49
+ * The minimal on-chain read surface easSource needs. Split out as an injection
50
+ * seam so the decode/aggregation path is unit-testable without a live chain
51
+ * (same pattern as erc8004.ts's ContractFactory). Real implementation reads
52
+ * Attested logs filtered by recipient + schema, then getAttestation per uid.
53
+ */
54
+ export interface AttestationReader {
55
+ /** UIDs of attestations of our schema whose recipient == seller. */
56
+ uidsForSeller(sellerAddress: string): Promise<string[]>;
57
+ /** The raw ABI-encoded `data` field of one attestation. */
58
+ dataForUid(uid: string): Promise<string>;
59
+ }
60
+ /** Build a real AttestationReader over a JSON-RPC endpoint (getLogs + getAttestation). */
61
+ export declare function rpcAttestationReader(rpcUrl: string, opts?: {
62
+ fromBlock?: number;
63
+ schemaUID?: string;
64
+ }): AttestationReader;
65
+ /**
66
+ * An untrusted ClaimSource backed by EAS. fetchForSeller reads the seller's
67
+ * attestation UIDs, decodes each back into a claim, and returns them. It does
68
+ * NOT verify (discoverDeliveryHistory does that for every source uniformly); it
69
+ * only drops entries that fail to decode into our claim shape. A malformed or
70
+ * hostile attestation therefore either fails to decode here or fails
71
+ * verifyClaim in discovery, never reaching the result as genuine.
72
+ */
73
+ export declare function easSource(reader: AttestationReader, name?: string): ClaimSource;
74
+ /** Convenience: an EAS-backed source directly from an RPC URL. */
75
+ export declare function easSourceFromRpc(rpcUrl: string, opts?: {
76
+ fromBlock?: number;
77
+ schemaUID?: string;
78
+ name?: string;
79
+ }): ClaimSource;
80
+ export { verifyClaim };
81
+ //# sourceMappingURL=eas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eas.d.ts","sourceRoot":"","sources":["../src/eas.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,eAAO,MAAM,WAAW,+CAA+C,CAAC;AACxE,eAAO,MAAM,uBAAuB,+CAA+C,CAAC;AAEpF,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAqCX,eAAO,MAAM,aAAa,iCAAiC,CAAC;AAG5D,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAAC,MAAM,SAAgB,EAAE,QAAQ,SAAqB,EAAE,SAAS,UAAmB,GAAG,MAAM,CAE5H;AAED,eAAO,MAAM,UAAU,QAAqB,CAAC;AAI7C,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAE5D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAgBlE;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUzE;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CA6BtG;AAMD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACxD,2DAA2D;IAC3D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1C;AAED,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,iBAAiB,CAqB7H;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,iBAAiB,EAAE,IAAI,SAAQ,GAAG,WAAW,CAmB9E;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,WAAW,CAElI;AAID,OAAO,EAAE,WAAW,EAAE,CAAC"}
package/dist/eas.js ADDED
@@ -0,0 +1,197 @@
1
+ // eas.ts — publish a delivery claim to, and discover it from, the Ethereum
2
+ // Attestation Service (EAS) on Base. This is the concrete, host-independent
3
+ // substrate D-005/D-012 pointed at: a public chain anyone can read, so a buyer
4
+ // on one installation can find a claim another buyer published, and verify it
5
+ // locally (discovery.ts re-verifies every claim, so EAS is just an untrusted
6
+ // ClaimSource like any other).
7
+ //
8
+ // Plain ethers only, no eas-sdk dependency. EAS is an OP-Stack predeploy, so
9
+ // the contract addresses are identical on Base mainnet (8453) and Base Sepolia
10
+ // (84532). Everything here is caller-parameterised (rpcUrl, signer): this
11
+ // package never bundles an RPC, a key, or gas, and never becomes the index.
12
+ //
13
+ // Verified against the EAS contract sources (IEAS.sol, Common.sol,
14
+ // SchemaRegistry.sol) and the base / base-sepolia deployment artifacts, 2026-09-06.
15
+ import { ethers } from "ethers";
16
+ import { DeliveryClaimSchema } from "./schema.js";
17
+ import { verifyClaim } from "./signing.js";
18
+ // OP-Stack predeploys: same on every Base network.
19
+ export const EAS_ADDRESS = "0x4200000000000000000000000000000000000021";
20
+ export const SCHEMA_REGISTRY_ADDRESS = "0x4200000000000000000000000000000000000020";
21
+ export const EAS_EXPLORER = {
22
+ 8453: "https://base.easscan.org",
23
+ 84532: "https://base-sepolia.easscan.org",
24
+ };
25
+ const EAS_ABI = [
26
+ "function attest((bytes32 schema,(address recipient,uint64 expirationTime,bool revocable,bytes32 refUID,bytes data,uint256 value) data) request) payable returns (bytes32)",
27
+ "function getAttestation(bytes32 uid) view returns ((bytes32 uid,bytes32 schema,uint64 time,uint64 expirationTime,uint64 revocationTime,bytes32 refUID,address recipient,address attester,bool revocable,bytes data))",
28
+ "event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID)",
29
+ ];
30
+ const SCHEMA_REGISTRY_ABI = [
31
+ "function register(string schema, address resolver, bool revocable) returns (bytes32)",
32
+ "function getSchema(bytes32 uid) view returns ((bytes32 uid,address resolver,bool revocable,string schema))",
33
+ ];
34
+ // Our schema. We carry the WHOLE signed claim as JSON in one field, so a
35
+ // discovered attestation is fully self-verifying offline (decode -> parse ->
36
+ // verifyClaim), with no second lookup anywhere. claimId is also stored as a
37
+ // bytes32 for a cheap on-chain cross-reference. Types + order are what matter
38
+ // for ABI-encoding; the names are metadata.
39
+ export const SCHEMA_STRING = "bytes32 claimId,string claim";
40
+ const SCHEMA_REVOCABLE = true;
41
+ /** Deterministic schema UID: keccak256(abi.encodePacked(schema, resolver, revocable)). */
42
+ export function computeSchemaUID(schema = SCHEMA_STRING, resolver = ethers.ZeroAddress, revocable = SCHEMA_REVOCABLE) {
43
+ return ethers.keccak256(ethers.solidityPacked(["string", "address", "bool"], [schema, resolver, revocable]));
44
+ }
45
+ export const SCHEMA_UID = computeSchemaUID();
46
+ const coder = ethers.AbiCoder.defaultAbiCoder();
47
+ /** ABI-encode a claim into EAS attestation data for SCHEMA_STRING. */
48
+ export function encodeClaimData(claim) {
49
+ return coder.encode(["bytes32", "string"], [claim.claimId, JSON.stringify(claim)]);
50
+ }
51
+ /**
52
+ * Decode EAS attestation data back into a claim. Returns null if the data does
53
+ * not decode or the JSON does not parse into our claim shape. NEVER trusts the
54
+ * result: the caller (easSource / discoverDeliveryHistory) re-verifies with
55
+ * verifyClaim. The on-chain bytes32 claimId is cross-checked against the JSON's
56
+ * own claimId, so a mismatch is dropped here as malformed.
57
+ */
58
+ export function decodeClaimData(data) {
59
+ let claimId;
60
+ let json;
61
+ try {
62
+ [claimId, json] = coder.decode(["bytes32", "string"], data);
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ let parsed;
68
+ try {
69
+ parsed = DeliveryClaimSchema.parse(JSON.parse(json));
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ if (parsed.claimId.toLowerCase() !== claimId.toLowerCase())
75
+ return null;
76
+ return parsed;
77
+ }
78
+ /**
79
+ * Register our schema if it does not already exist on this chain. The schema
80
+ * UID is deterministic, so a duplicate register() reverts with AlreadyExists;
81
+ * we check first via getSchema and only register when absent. Requires a
82
+ * funded signer. Returns the schema UID.
83
+ */
84
+ export async function ensureSchema(signer) {
85
+ const registry = new ethers.Contract(SCHEMA_REGISTRY_ADDRESS, SCHEMA_REGISTRY_ABI, signer);
86
+ const existing = await registry.getSchema(SCHEMA_UID);
87
+ // getSchema returns a zero-uid struct when the schema is not registered.
88
+ if (existing && existing.uid && existing.uid.toLowerCase() === SCHEMA_UID.toLowerCase()) {
89
+ return SCHEMA_UID;
90
+ }
91
+ const tx = await registry.register(SCHEMA_STRING, ethers.ZeroAddress, SCHEMA_REVOCABLE);
92
+ await tx.wait();
93
+ return SCHEMA_UID;
94
+ }
95
+ /**
96
+ * Publish one claim to EAS as an attestation with recipient = sellerAddress, so
97
+ * it is discoverable by that seller. `signer` only pays gas and writes the
98
+ * transaction; it does not need to be, and normally is not, the buyer. The
99
+ * buyer identity lives entirely inside `claim` (buyerAddress, checked by
100
+ * verifyClaim against the signature over claimId): nothing on the read path
101
+ * (easSource, discoverDeliveryHistory) ever looks at who published the
102
+ * attestation, only at what the claim itself proves. Requires a funded signer.
103
+ * Returns the new attestation UID and tx hash.
104
+ */
105
+ export async function publishClaim(signer, claim) {
106
+ const eas = new ethers.Contract(EAS_ADDRESS, EAS_ABI, signer);
107
+ const tx = await eas.attest({
108
+ schema: SCHEMA_UID,
109
+ data: {
110
+ recipient: claim.sellerAddress,
111
+ expirationTime: 0n,
112
+ revocable: SCHEMA_REVOCABLE,
113
+ refUID: ethers.ZeroHash,
114
+ data: encodeClaimData(claim),
115
+ value: 0n,
116
+ },
117
+ });
118
+ const receipt = await tx.wait();
119
+ if (!receipt)
120
+ throw new Error("attest transaction had no receipt (dropped or replaced)");
121
+ const iface = new ethers.Interface(EAS_ABI);
122
+ let uid = "";
123
+ for (const log of receipt.logs) {
124
+ try {
125
+ const parsed = iface.parseLog(log);
126
+ if (parsed && parsed.name === "Attested") {
127
+ uid = parsed.args.uid;
128
+ break;
129
+ }
130
+ }
131
+ catch {
132
+ // not an EAS log, skip
133
+ }
134
+ }
135
+ return { uid, txHash: receipt.hash, recipient: claim.sellerAddress };
136
+ }
137
+ /** Build a real AttestationReader over a JSON-RPC endpoint (getLogs + getAttestation). */
138
+ export function rpcAttestationReader(rpcUrl, opts = {}) {
139
+ const provider = new ethers.JsonRpcProvider(rpcUrl);
140
+ const eas = new ethers.Contract(EAS_ADDRESS, EAS_ABI, provider);
141
+ const schemaUID = opts.schemaUID ?? SCHEMA_UID;
142
+ const attestedTopic0 = ethers.id("Attested(address,address,bytes32,bytes32)");
143
+ return {
144
+ uidsForSeller: async (sellerAddress) => {
145
+ const logs = await provider.getLogs({
146
+ address: EAS_ADDRESS,
147
+ topics: [attestedTopic0, ethers.zeroPadValue(sellerAddress, 32), null, schemaUID],
148
+ fromBlock: opts.fromBlock ?? 0,
149
+ toBlock: "latest",
150
+ });
151
+ // uid is the only non-indexed value: it sits in log.data.
152
+ return logs.map((l) => l.data);
153
+ },
154
+ dataForUid: async (uid) => {
155
+ const att = await eas.getAttestation(uid);
156
+ return att.data;
157
+ },
158
+ };
159
+ }
160
+ /**
161
+ * An untrusted ClaimSource backed by EAS. fetchForSeller reads the seller's
162
+ * attestation UIDs, decodes each back into a claim, and returns them. It does
163
+ * NOT verify (discoverDeliveryHistory does that for every source uniformly); it
164
+ * only drops entries that fail to decode into our claim shape. A malformed or
165
+ * hostile attestation therefore either fails to decode here or fails
166
+ * verifyClaim in discovery, never reaching the result as genuine.
167
+ */
168
+ export function easSource(reader, name = "eas") {
169
+ return {
170
+ name,
171
+ fetchForSeller: async (sellerAddress) => {
172
+ const uids = await reader.uidsForSeller(sellerAddress);
173
+ const claims = [];
174
+ for (const uid of uids) {
175
+ let data;
176
+ try {
177
+ data = await reader.dataForUid(uid);
178
+ }
179
+ catch {
180
+ continue; // unreadable attestation, skip
181
+ }
182
+ const claim = decodeClaimData(data);
183
+ if (claim)
184
+ claims.push(claim);
185
+ }
186
+ return claims;
187
+ },
188
+ };
189
+ }
190
+ /** Convenience: an EAS-backed source directly from an RPC URL. */
191
+ export function easSourceFromRpc(rpcUrl, opts = {}) {
192
+ return easSource(rpcAttestationReader(rpcUrl, opts), opts.name ?? "eas");
193
+ }
194
+ // Re-export so callers see verifyClaim is what makes an EAS-sourced claim
195
+ // trustworthy, not EAS itself.
196
+ export { verifyClaim };
197
+ //# sourceMappingURL=eas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eas.js","sourceRoot":"","sources":["../src/eas.ts"],"names":[],"mappings":"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"}