capacity-attest 0.5.0 → 0.7.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/LICENSE +21 -0
- package/README.md +208 -167
- package/README.nl.md +204 -0
- package/dist/bench-helpers.d.ts +12 -0
- package/dist/bench-helpers.d.ts.map +1 -0
- package/dist/bench-helpers.js +51 -0
- package/dist/bench-helpers.js.map +1 -0
- package/dist/discovery.bench.d.ts +2 -0
- package/dist/discovery.bench.d.ts.map +1 -0
- package/dist/discovery.bench.js +30 -0
- package/dist/discovery.bench.js.map +1 -0
- package/dist/discovery.d.ts +2 -0
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +57 -2
- package/dist/discovery.js.map +1 -1
- package/dist/eas.bench.d.ts +2 -0
- package/dist/eas.bench.d.ts.map +1 -0
- package/dist/eas.bench.js +40 -0
- package/dist/eas.bench.js.map +1 -0
- package/dist/eas.d.ts +96 -10
- package/dist/eas.d.ts.map +1 -1
- package/dist/eas.js +158 -37
- package/dist/eas.js.map +1 -1
- package/dist/erc8004-reputation.d.ts +110 -0
- package/dist/erc8004-reputation.d.ts.map +1 -0
- package/dist/erc8004-reputation.js +203 -0
- package/dist/erc8004-reputation.js.map +1 -0
- package/dist/erc8004.d.ts +3 -1
- package/dist/erc8004.d.ts.map +1 -1
- package/dist/erc8004.js +20 -4
- package/dist/erc8004.js.map +1 -1
- package/dist/http-source.bench.d.ts +2 -0
- package/dist/http-source.bench.d.ts.map +1 -0
- package/dist/http-source.bench.js +65 -0
- package/dist/http-source.bench.js.map +1 -0
- package/dist/http-source.d.ts +28 -0
- package/dist/http-source.d.ts.map +1 -0
- package/dist/http-source.js +154 -0
- package/dist/http-source.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +93 -5
- package/dist/ledger.js.map +1 -1
- package/dist/schema.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +14 -2
- package/dist/schema.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +6 -1
- package/dist/tools.js.map +1 -1
- package/package.json +63 -58
package/dist/eas.d.ts
CHANGED
|
@@ -4,10 +4,44 @@ import { verifyClaim } from "./signing.js";
|
|
|
4
4
|
import type { ClaimSource } from "./discovery.js";
|
|
5
5
|
export declare const EAS_ADDRESS = "0x4200000000000000000000000000000000000021";
|
|
6
6
|
export declare const SCHEMA_REGISTRY_ADDRESS = "0x4200000000000000000000000000000000000020";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
/** One chain's EAS deployment: both contract addresses, plus a human-facing explorer base URL. */
|
|
8
|
+
export interface EasDeployment {
|
|
9
|
+
chainId: number;
|
|
10
|
+
name: string;
|
|
11
|
+
easAddress: string;
|
|
12
|
+
schemaRegistryAddress: string;
|
|
13
|
+
explorer: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Known EAS deployments, keyed by chainId. Every address was independently
|
|
17
|
+
* verified (EAS's own deployment records AND a live eth_getCode call)
|
|
18
|
+
* before being added here -- the OP-Stack-predeploy pattern is CONFIRMED
|
|
19
|
+
* true for Optimism specifically below, never applied to a new chain just
|
|
20
|
+
* because it sounds plausible.
|
|
21
|
+
*/
|
|
22
|
+
export declare const EAS_DEPLOYMENTS: Record<number, EasDeployment>;
|
|
23
|
+
/** Backward-compatible: existing callers (examples/eas-live-demo.ts) look up an explorer URL by chainId this way. Derived FROM EAS_DEPLOYMENTS so there is exactly one source of truth, not two tables that could quietly drift apart. */
|
|
24
|
+
export declare const EAS_EXPLORER: Record<number, string>;
|
|
25
|
+
interface AttestRequest {
|
|
26
|
+
schema: string;
|
|
27
|
+
data: {
|
|
28
|
+
recipient: string;
|
|
29
|
+
expirationTime: bigint;
|
|
30
|
+
revocable: boolean;
|
|
31
|
+
refUID: string;
|
|
32
|
+
data: string;
|
|
33
|
+
value: bigint;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
interface EasWriteContract {
|
|
37
|
+
attest(request: AttestRequest): Promise<ethers.ContractTransactionResponse>;
|
|
38
|
+
}
|
|
39
|
+
interface SchemaRegistryContract {
|
|
40
|
+
getSchema(uid: string): Promise<{
|
|
41
|
+
uid: string;
|
|
42
|
+
}>;
|
|
43
|
+
register(schema: string, resolver: string, revocable: boolean): Promise<ethers.ContractTransactionResponse>;
|
|
44
|
+
}
|
|
11
45
|
export declare const SCHEMA_STRING = "bytes32 claimId,string claim";
|
|
12
46
|
/** Deterministic schema UID: keccak256(abi.encodePacked(schema, resolver, revocable)). */
|
|
13
47
|
export declare function computeSchemaUID(schema?: string, resolver?: string, revocable?: boolean): string;
|
|
@@ -22,25 +56,55 @@ export declare function encodeClaimData(claim: DeliveryClaim): string;
|
|
|
22
56
|
* own claimId, so a mismatch is dropped here as malformed.
|
|
23
57
|
*/
|
|
24
58
|
export declare function decodeClaimData(data: string): DeliveryClaim | null;
|
|
59
|
+
/**
|
|
60
|
+
* Builds the SchemaRegistry write contract. Split out as an injection seam
|
|
61
|
+
* (same DI pattern as erc8004.ts's ContractFactory and this file's own
|
|
62
|
+
* AttestationReader below) so ensureSchema's CHAIN-TARGETING logic --
|
|
63
|
+
* "does it use the address I told it to, for a chain that is not Base" --
|
|
64
|
+
* is unit-testable without a live signer or network, not just assumed.
|
|
65
|
+
*/
|
|
66
|
+
export type SchemaRegistryContractFactory = (schemaRegistryAddress: string, signer: ethers.Signer) => SchemaRegistryContract;
|
|
25
67
|
/**
|
|
26
68
|
* Register our schema if it does not already exist on this chain. The schema
|
|
27
69
|
* UID is deterministic, so a duplicate register() reverts with AlreadyExists;
|
|
28
70
|
* we check first via getSchema and only register when absent. Requires a
|
|
29
71
|
* funded signer. Returns the schema UID.
|
|
72
|
+
*
|
|
73
|
+
* `opts.schemaRegistryAddress` defaults to SCHEMA_REGISTRY_ADDRESS (Base's,
|
|
74
|
+
* unchanged from before this function took an opts argument at all): pass
|
|
75
|
+
* `EAS_DEPLOYMENTS[1].schemaRegistryAddress` for Ethereum mainnet, or any
|
|
76
|
+
* other chain's own address, to target that chain instead.
|
|
30
77
|
*/
|
|
31
|
-
export declare function ensureSchema(signer: ethers.Signer
|
|
78
|
+
export declare function ensureSchema(signer: ethers.Signer, opts?: {
|
|
79
|
+
schemaRegistryAddress?: string;
|
|
80
|
+
contractFactory?: SchemaRegistryContractFactory;
|
|
81
|
+
}): Promise<string>;
|
|
32
82
|
export interface PublishResult {
|
|
33
83
|
uid: string;
|
|
34
84
|
txHash: string;
|
|
35
85
|
recipient: string;
|
|
36
86
|
}
|
|
87
|
+
/** Same injection-seam purpose as SchemaRegistryContractFactory above, for the EAS write contract itself. */
|
|
88
|
+
export type EasWriteContractFactory = (easAddress: string, signer: ethers.Signer) => EasWriteContract;
|
|
37
89
|
/**
|
|
38
90
|
* Publish one claim to EAS as an attestation with recipient = sellerAddress, so
|
|
39
|
-
* it is discoverable by that seller.
|
|
40
|
-
*
|
|
41
|
-
*
|
|
91
|
+
* it is discoverable by that seller. `signer` only pays gas and writes the
|
|
92
|
+
* transaction; it does not need to be, and normally is not, the buyer. The
|
|
93
|
+
* buyer identity lives entirely inside `claim` (buyerAddress, checked by
|
|
94
|
+
* verifyClaim against the signature over claimId): nothing on the read path
|
|
95
|
+
* (easSource, discoverDeliveryHistory) ever looks at who published the
|
|
96
|
+
* attestation, only at what the claim itself proves. Requires a funded signer.
|
|
97
|
+
* Returns the new attestation UID and tx hash.
|
|
98
|
+
*
|
|
99
|
+
* `opts.easAddress` defaults to EAS_ADDRESS (Base's, unchanged from before
|
|
100
|
+
* this function took an opts argument at all): pass
|
|
101
|
+
* `EAS_DEPLOYMENTS[1].easAddress` for Ethereum mainnet, or any other
|
|
102
|
+
* chain's own address, to target that chain instead.
|
|
42
103
|
*/
|
|
43
|
-
export declare function publishClaim(signer: ethers.Signer, claim: DeliveryClaim
|
|
104
|
+
export declare function publishClaim(signer: ethers.Signer, claim: DeliveryClaim, opts?: {
|
|
105
|
+
easAddress?: string;
|
|
106
|
+
contractFactory?: EasWriteContractFactory;
|
|
107
|
+
}): Promise<PublishResult>;
|
|
44
108
|
/**
|
|
45
109
|
* The minimal on-chain read surface easSource needs. Split out as an injection
|
|
46
110
|
* seam so the decode/aggregation path is unit-testable without a live chain
|
|
@@ -52,11 +116,30 @@ export interface AttestationReader {
|
|
|
52
116
|
uidsForSeller(sellerAddress: string): Promise<string[]>;
|
|
53
117
|
/** The raw ABI-encoded `data` field of one attestation. */
|
|
54
118
|
dataForUid(uid: string): Promise<string>;
|
|
119
|
+
/** Max concurrent dataForUid calls easSource should keep in flight. Readers that do not set this get DEFAULT_CONCURRENCY. */
|
|
120
|
+
concurrency?: number;
|
|
55
121
|
}
|
|
56
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* Pure block-range windowing, split out so the chunking math is unit-testable
|
|
124
|
+
* without a real or mocked RPC provider. [fromBlock, latest] inclusive,
|
|
125
|
+
* chunked into <= blockRange-wide, non-overlapping, gap-free windows in
|
|
126
|
+
* ascending order. Returns [] when fromBlock > latest (nothing to scan).
|
|
127
|
+
*/
|
|
128
|
+
export declare function blockWindows(fromBlock: number, latest: number, blockRange: number): Array<[number, number]>;
|
|
129
|
+
/**
|
|
130
|
+
* Build a real AttestationReader over a JSON-RPC endpoint (getLogs +
|
|
131
|
+
* getAttestation). `opts.easAddress` defaults to EAS_ADDRESS (Base's,
|
|
132
|
+
* unchanged from before WP2): pass `EAS_DEPLOYMENTS[1].easAddress` for
|
|
133
|
+
* Ethereum mainnet, or any other chain's own address, to read that chain
|
|
134
|
+
* instead. rpcUrl itself already told this function which CHAIN to talk to;
|
|
135
|
+
* easAddress tells it WHERE on that chain the EAS contract lives.
|
|
136
|
+
*/
|
|
57
137
|
export declare function rpcAttestationReader(rpcUrl: string, opts?: {
|
|
58
138
|
fromBlock?: number;
|
|
59
139
|
schemaUID?: string;
|
|
140
|
+
blockRange?: number;
|
|
141
|
+
concurrency?: number;
|
|
142
|
+
easAddress?: string;
|
|
60
143
|
}): AttestationReader;
|
|
61
144
|
/**
|
|
62
145
|
* An untrusted ClaimSource backed by EAS. fetchForSeller reads the seller's
|
|
@@ -72,6 +155,9 @@ export declare function easSourceFromRpc(rpcUrl: string, opts?: {
|
|
|
72
155
|
fromBlock?: number;
|
|
73
156
|
schemaUID?: string;
|
|
74
157
|
name?: string;
|
|
158
|
+
blockRange?: number;
|
|
159
|
+
concurrency?: number;
|
|
160
|
+
easAddress?: string;
|
|
75
161
|
}): ClaimSource;
|
|
76
162
|
export { verifyClaim };
|
|
77
163
|
//# sourceMappingURL=eas.d.ts.map
|
package/dist/eas.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eas.d.ts","sourceRoot":"","sources":["../src/eas.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"eas.d.ts","sourceRoot":"","sources":["../src/eas.ts"],"names":[],"mappings":"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"}
|
package/dist/eas.js
CHANGED
|
@@ -1,27 +1,57 @@
|
|
|
1
1
|
// eas.ts — publish a delivery claim to, and discover it from, the Ethereum
|
|
2
|
-
// Attestation Service (EAS)
|
|
2
|
+
// Attestation Service (EAS). This is the concrete, host-independent
|
|
3
3
|
// substrate D-005/D-012 pointed at: a public chain anyone can read, so a buyer
|
|
4
4
|
// on one installation can find a claim another buyer published, and verify it
|
|
5
5
|
// locally (discovery.ts re-verifies every claim, so EAS is just an untrusted
|
|
6
6
|
// ClaimSource like any other).
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
8
|
+
// Originally wired to Base only. Generalized here (WP2, see
|
|
9
|
+
// docs/NLNET-SELFBUILD-PLAN-2026-09-28.md) to support any EAS deployment:
|
|
10
|
+
// discovery.ts's own header comment always described the substrate as "EAS
|
|
11
|
+
// on Base", not "EAS, forever only Base". Optimism and Ethereum mainnet are
|
|
12
|
+
// equally real EAS deployments, just with different contract addresses:
|
|
13
|
+
// Optimism, being an OP-Stack chain like Base, happens to share Base's exact
|
|
14
|
+
// predeploy addresses; Ethereum mainnet does not, since it is the underlying
|
|
15
|
+
// L1, not an OP-Stack chain. That distinction was verified, not assumed --
|
|
16
|
+
// see EAS_DEPLOYMENTS below.
|
|
17
|
+
//
|
|
18
|
+
// Plain ethers only, no eas-sdk dependency. Everything here is
|
|
19
|
+
// caller-parameterised (rpcUrl, signer, and now chain addresses too): this
|
|
11
20
|
// package never bundles an RPC, a key, or gas, and never becomes the index.
|
|
12
21
|
//
|
|
13
|
-
//
|
|
14
|
-
// SchemaRegistry.sol) and the base / base-sepolia deployment
|
|
22
|
+
// Base's addresses verified against the EAS contract sources (IEAS.sol,
|
|
23
|
+
// Common.sol, SchemaRegistry.sol) and the base / base-sepolia deployment
|
|
24
|
+
// artifacts, 2026-09-06. Optimism and Ethereum mainnet addresses verified
|
|
25
|
+
// 2026-09-28 against EAS's own official deployment records
|
|
26
|
+
// (github.com/ethereum-attestation-service/eas-contracts, the
|
|
27
|
+
// deployments/optimism and deployments/mainnet JSON files, cross-checked
|
|
28
|
+
// against docs.attest.org's own contracts table) AND independently
|
|
29
|
+
// re-confirmed with a direct eth_getCode call against each chain's real,
|
|
30
|
+
// live RPC: real bytecode present at every address below, not just "found
|
|
31
|
+
// in a document".
|
|
15
32
|
import { ethers } from "ethers";
|
|
16
33
|
import { DeliveryClaimSchema } from "./schema.js";
|
|
17
34
|
import { verifyClaim } from "./signing.js";
|
|
18
|
-
// OP-Stack predeploys:
|
|
35
|
+
// OP-Stack predeploys: identical on every OP-Stack chain (Base, Optimism).
|
|
36
|
+
// Kept as the module-level default for every function below, so a caller who
|
|
37
|
+
// passes nothing still gets exactly today's, unchanged, Base behavior.
|
|
19
38
|
export const EAS_ADDRESS = "0x4200000000000000000000000000000000000021";
|
|
20
39
|
export const SCHEMA_REGISTRY_ADDRESS = "0x4200000000000000000000000000000000000020";
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Known EAS deployments, keyed by chainId. Every address was independently
|
|
42
|
+
* verified (EAS's own deployment records AND a live eth_getCode call)
|
|
43
|
+
* before being added here -- the OP-Stack-predeploy pattern is CONFIRMED
|
|
44
|
+
* true for Optimism specifically below, never applied to a new chain just
|
|
45
|
+
* because it sounds plausible.
|
|
46
|
+
*/
|
|
47
|
+
export const EAS_DEPLOYMENTS = {
|
|
48
|
+
8453: { chainId: 8453, name: "Base", easAddress: EAS_ADDRESS, schemaRegistryAddress: SCHEMA_REGISTRY_ADDRESS, explorer: "https://base.easscan.org" },
|
|
49
|
+
84532: { chainId: 84532, name: "Base Sepolia", easAddress: EAS_ADDRESS, schemaRegistryAddress: SCHEMA_REGISTRY_ADDRESS, explorer: "https://base-sepolia.easscan.org" },
|
|
50
|
+
10: { chainId: 10, name: "Optimism", easAddress: EAS_ADDRESS, schemaRegistryAddress: SCHEMA_REGISTRY_ADDRESS, explorer: "https://optimism.easscan.org" },
|
|
51
|
+
1: { chainId: 1, name: "Ethereum", easAddress: "0xA1207F3BBa224E2c9c3c6D5aF63D0eb1582Ce587", schemaRegistryAddress: "0xA7b39296258348C78294F95B872b282326A97BDF", explorer: "https://easscan.org" },
|
|
24
52
|
};
|
|
53
|
+
/** Backward-compatible: existing callers (examples/eas-live-demo.ts) look up an explorer URL by chainId this way. Derived FROM EAS_DEPLOYMENTS so there is exactly one source of truth, not two tables that could quietly drift apart. */
|
|
54
|
+
export const EAS_EXPLORER = Object.fromEntries(Object.entries(EAS_DEPLOYMENTS).map(([chainId, d]) => [chainId, d.explorer]));
|
|
25
55
|
const EAS_ABI = [
|
|
26
56
|
"function attest((bytes32 schema,(address recipient,uint64 expirationTime,bool revocable,bytes32 refUID,bytes data,uint256 value) data) request) payable returns (bytes32)",
|
|
27
57
|
"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))",
|
|
@@ -75,14 +105,22 @@ export function decodeClaimData(data) {
|
|
|
75
105
|
return null;
|
|
76
106
|
return parsed;
|
|
77
107
|
}
|
|
108
|
+
const defaultSchemaRegistryContractFactory = (schemaRegistryAddress, signer) => new ethers.Contract(schemaRegistryAddress, SCHEMA_REGISTRY_ABI, signer);
|
|
78
109
|
/**
|
|
79
110
|
* Register our schema if it does not already exist on this chain. The schema
|
|
80
111
|
* UID is deterministic, so a duplicate register() reverts with AlreadyExists;
|
|
81
112
|
* we check first via getSchema and only register when absent. Requires a
|
|
82
113
|
* funded signer. Returns the schema UID.
|
|
114
|
+
*
|
|
115
|
+
* `opts.schemaRegistryAddress` defaults to SCHEMA_REGISTRY_ADDRESS (Base's,
|
|
116
|
+
* unchanged from before this function took an opts argument at all): pass
|
|
117
|
+
* `EAS_DEPLOYMENTS[1].schemaRegistryAddress` for Ethereum mainnet, or any
|
|
118
|
+
* other chain's own address, to target that chain instead.
|
|
83
119
|
*/
|
|
84
|
-
export async function ensureSchema(signer) {
|
|
85
|
-
const
|
|
120
|
+
export async function ensureSchema(signer, opts = {}) {
|
|
121
|
+
const schemaRegistryAddress = opts.schemaRegistryAddress ?? SCHEMA_REGISTRY_ADDRESS;
|
|
122
|
+
const contractFactory = opts.contractFactory ?? defaultSchemaRegistryContractFactory;
|
|
123
|
+
const registry = contractFactory(schemaRegistryAddress, signer);
|
|
86
124
|
const existing = await registry.getSchema(SCHEMA_UID);
|
|
87
125
|
// getSchema returns a zero-uid struct when the schema is not registered.
|
|
88
126
|
if (existing && existing.uid && existing.uid.toLowerCase() === SCHEMA_UID.toLowerCase()) {
|
|
@@ -92,14 +130,26 @@ export async function ensureSchema(signer) {
|
|
|
92
130
|
await tx.wait();
|
|
93
131
|
return SCHEMA_UID;
|
|
94
132
|
}
|
|
133
|
+
const defaultEasWriteContractFactory = (easAddress, signer) => new ethers.Contract(easAddress, EAS_ABI, signer);
|
|
95
134
|
/**
|
|
96
135
|
* Publish one claim to EAS as an attestation with recipient = sellerAddress, so
|
|
97
|
-
* it is discoverable by that seller.
|
|
98
|
-
*
|
|
99
|
-
*
|
|
136
|
+
* it is discoverable by that seller. `signer` only pays gas and writes the
|
|
137
|
+
* transaction; it does not need to be, and normally is not, the buyer. The
|
|
138
|
+
* buyer identity lives entirely inside `claim` (buyerAddress, checked by
|
|
139
|
+
* verifyClaim against the signature over claimId): nothing on the read path
|
|
140
|
+
* (easSource, discoverDeliveryHistory) ever looks at who published the
|
|
141
|
+
* attestation, only at what the claim itself proves. Requires a funded signer.
|
|
142
|
+
* Returns the new attestation UID and tx hash.
|
|
143
|
+
*
|
|
144
|
+
* `opts.easAddress` defaults to EAS_ADDRESS (Base's, unchanged from before
|
|
145
|
+
* this function took an opts argument at all): pass
|
|
146
|
+
* `EAS_DEPLOYMENTS[1].easAddress` for Ethereum mainnet, or any other
|
|
147
|
+
* chain's own address, to target that chain instead.
|
|
100
148
|
*/
|
|
101
|
-
export async function publishClaim(signer, claim) {
|
|
102
|
-
const
|
|
149
|
+
export async function publishClaim(signer, claim, opts = {}) {
|
|
150
|
+
const easAddress = opts.easAddress ?? EAS_ADDRESS;
|
|
151
|
+
const contractFactory = opts.contractFactory ?? defaultEasWriteContractFactory;
|
|
152
|
+
const eas = contractFactory(easAddress, signer);
|
|
103
153
|
const tx = await eas.attest({
|
|
104
154
|
schema: SCHEMA_UID,
|
|
105
155
|
data: {
|
|
@@ -130,27 +180,83 @@ export async function publishClaim(signer, claim) {
|
|
|
130
180
|
}
|
|
131
181
|
return { uid, txHash: receipt.hash, recipient: claim.sellerAddress };
|
|
132
182
|
}
|
|
133
|
-
|
|
183
|
+
// Most public RPC providers cap a single eth_getLogs call to a bounded block
|
|
184
|
+
// range (2,000-10,000 blocks is typical; some reject an unbounded fromBlock=0
|
|
185
|
+
// outright). A single call from genesis to "latest" therefore either errors
|
|
186
|
+
// out or silently degrades depending on the provider, and degrades further as
|
|
187
|
+
// the chain ages and the range grows. Default window chosen conservatively
|
|
188
|
+
// below the tightest commonly-seen provider limit; callers on a more
|
|
189
|
+
// permissive RPC can raise it via opts.blockRange.
|
|
190
|
+
const DEFAULT_BLOCK_RANGE = 2_000;
|
|
191
|
+
// Bound how many attestation bodies rpcAttestationReader fetches CONCURRENTLY
|
|
192
|
+
// per uidsForSeller/dataForUid fan-out. discoverDeliveryHistory's own
|
|
193
|
+
// MAX_CLAIMS_PER_SOURCE bounds how many claims are ultimately ACCEPTED from a
|
|
194
|
+
// source; this bounds how many in-flight RPC requests a single source's read
|
|
195
|
+
// can open at once, so a seller with many attestations does not open
|
|
196
|
+
// thousands of simultaneous connections against the RPC endpoint.
|
|
197
|
+
const DEFAULT_CONCURRENCY = 10;
|
|
198
|
+
/**
|
|
199
|
+
* Pure block-range windowing, split out so the chunking math is unit-testable
|
|
200
|
+
* without a real or mocked RPC provider. [fromBlock, latest] inclusive,
|
|
201
|
+
* chunked into <= blockRange-wide, non-overlapping, gap-free windows in
|
|
202
|
+
* ascending order. Returns [] when fromBlock > latest (nothing to scan).
|
|
203
|
+
*/
|
|
204
|
+
export function blockWindows(fromBlock, latest, blockRange) {
|
|
205
|
+
if (blockRange < 1)
|
|
206
|
+
throw new Error(`blockRange must be >= 1, got ${blockRange}`);
|
|
207
|
+
const windows = [];
|
|
208
|
+
for (let from = fromBlock; from <= latest; from += blockRange) {
|
|
209
|
+
windows.push([from, Math.min(from + blockRange - 1, latest)]);
|
|
210
|
+
}
|
|
211
|
+
return windows;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Build a real AttestationReader over a JSON-RPC endpoint (getLogs +
|
|
215
|
+
* getAttestation). `opts.easAddress` defaults to EAS_ADDRESS (Base's,
|
|
216
|
+
* unchanged from before WP2): pass `EAS_DEPLOYMENTS[1].easAddress` for
|
|
217
|
+
* Ethereum mainnet, or any other chain's own address, to read that chain
|
|
218
|
+
* instead. rpcUrl itself already told this function which CHAIN to talk to;
|
|
219
|
+
* easAddress tells it WHERE on that chain the EAS contract lives.
|
|
220
|
+
*/
|
|
134
221
|
export function rpcAttestationReader(rpcUrl, opts = {}) {
|
|
135
222
|
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
136
|
-
const
|
|
223
|
+
const easAddress = opts.easAddress ?? EAS_ADDRESS;
|
|
224
|
+
const eas = new ethers.Contract(easAddress, EAS_ABI, provider);
|
|
137
225
|
const schemaUID = opts.schemaUID ?? SCHEMA_UID;
|
|
138
226
|
const attestedTopic0 = ethers.id("Attested(address,address,bytes32,bytes32)");
|
|
227
|
+
const blockRange = opts.blockRange ?? DEFAULT_BLOCK_RANGE;
|
|
228
|
+
const concurrency = opts.concurrency ?? DEFAULT_CONCURRENCY;
|
|
139
229
|
return {
|
|
140
230
|
uidsForSeller: async (sellerAddress) => {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
//
|
|
148
|
-
|
|
231
|
+
const latest = await provider.getBlockNumber();
|
|
232
|
+
const windows = blockWindows(opts.fromBlock ?? 0, latest, blockRange);
|
|
233
|
+
const uids = [];
|
|
234
|
+
// Walk the chain in bounded windows instead of one fromBlock=0..latest
|
|
235
|
+
// call. A window that itself errors (provider-side limit stricter than
|
|
236
|
+
// blockRange) is not swallowed here: it propagates, same as today's
|
|
237
|
+
// single-call behaviour, so a caller who needs resilience against a
|
|
238
|
+
// flaky/stricter provider passes a smaller blockRange, not a silent
|
|
239
|
+
// partial result.
|
|
240
|
+
for (const [from, to] of windows) {
|
|
241
|
+
const logs = await provider.getLogs({
|
|
242
|
+
address: easAddress,
|
|
243
|
+
topics: [attestedTopic0, ethers.zeroPadValue(sellerAddress, 32), null, schemaUID],
|
|
244
|
+
fromBlock: from,
|
|
245
|
+
toBlock: to,
|
|
246
|
+
});
|
|
247
|
+
// uid is the only non-indexed value: it sits in log.data.
|
|
248
|
+
for (const l of logs)
|
|
249
|
+
uids.push(l.data);
|
|
250
|
+
}
|
|
251
|
+
return uids;
|
|
149
252
|
},
|
|
150
253
|
dataForUid: async (uid) => {
|
|
151
254
|
const att = await eas.getAttestation(uid);
|
|
152
255
|
return att.data;
|
|
153
256
|
},
|
|
257
|
+
// Exposed so easSource's fan-out can bound concurrency without
|
|
258
|
+
// hardcoding a number that belongs to the reader's own configuration.
|
|
259
|
+
concurrency,
|
|
154
260
|
};
|
|
155
261
|
}
|
|
156
262
|
/**
|
|
@@ -166,19 +272,34 @@ export function easSource(reader, name = "eas") {
|
|
|
166
272
|
name,
|
|
167
273
|
fetchForSeller: async (sellerAddress) => {
|
|
168
274
|
const uids = await reader.uidsForSeller(sellerAddress);
|
|
275
|
+
const concurrency = Math.max(1, reader.concurrency ?? DEFAULT_CONCURRENCY);
|
|
169
276
|
const claims = [];
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
277
|
+
// Bounded-concurrency fan-out: at most `concurrency` dataForUid calls
|
|
278
|
+
// in flight at once, instead of either one-at-a-time (slow for a
|
|
279
|
+
// seller with many attestations) or fully unbounded (many simultaneous
|
|
280
|
+
// requests against one RPC endpoint). Order of `claims` does not need
|
|
281
|
+
// to match `uids`; discoverDeliveryHistory sorts the final aggregate by
|
|
282
|
+
// timestamp regardless of source order.
|
|
283
|
+
let next = 0;
|
|
284
|
+
async function worker() {
|
|
285
|
+
for (;;) {
|
|
286
|
+
const i = next++;
|
|
287
|
+
if (i >= uids.length)
|
|
288
|
+
return;
|
|
289
|
+
const uid = uids[i];
|
|
290
|
+
let data;
|
|
291
|
+
try {
|
|
292
|
+
data = await reader.dataForUid(uid);
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
continue; // unreadable attestation, skip
|
|
296
|
+
}
|
|
297
|
+
const claim = decodeClaimData(data);
|
|
298
|
+
if (claim)
|
|
299
|
+
claims.push(claim);
|
|
177
300
|
}
|
|
178
|
-
const claim = decodeClaimData(data);
|
|
179
|
-
if (claim)
|
|
180
|
-
claims.push(claim);
|
|
181
301
|
}
|
|
302
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, uids.length) }, worker));
|
|
182
303
|
return claims;
|
|
183
304
|
},
|
|
184
305
|
};
|
package/dist/eas.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eas.js","sourceRoot":"","sources":["../src/eas.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,
|
|
1
|
+
{"version":3,"file":"eas.js","sourceRoot":"","sources":["../src/eas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { ethers } from "ethers";
|
|
2
|
+
import * as z from "zod/v4";
|
|
3
|
+
import { resolveAgentIdentity } from "./erc8004.js";
|
|
4
|
+
export declare const PublishReputationFeedbackInputSchema: z.ZodObject<{
|
|
5
|
+
reputationRegistryRef: z.ZodString;
|
|
6
|
+
agentRegistryRef: z.ZodString;
|
|
7
|
+
agentId: z.ZodString;
|
|
8
|
+
rpcUrl: z.ZodString;
|
|
9
|
+
claim: z.ZodObject<{
|
|
10
|
+
sellerAddress: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
11
|
+
buyerAddress: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
12
|
+
assetType: z.ZodEnum<{
|
|
13
|
+
"gpu-hours": "gpu-hours";
|
|
14
|
+
storage: "storage";
|
|
15
|
+
"api-credits": "api-credits";
|
|
16
|
+
bandwidth: "bandwidth";
|
|
17
|
+
}>;
|
|
18
|
+
promisedSpec: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
|
|
19
|
+
delivered: z.ZodEnum<{
|
|
20
|
+
yes: "yes";
|
|
21
|
+
no: "no";
|
|
22
|
+
partial: "partial";
|
|
23
|
+
}>;
|
|
24
|
+
evidenceHash: z.ZodString;
|
|
25
|
+
settlementRef: z.ZodString;
|
|
26
|
+
timestamp: z.ZodString;
|
|
27
|
+
measured: z.ZodOptional<z.ZodObject<{
|
|
28
|
+
unit: z.ZodEnum<{
|
|
29
|
+
"gpu-second": "gpu-second";
|
|
30
|
+
byte: "byte";
|
|
31
|
+
"byte-second": "byte-second";
|
|
32
|
+
call: "call";
|
|
33
|
+
token: "token";
|
|
34
|
+
credit: "credit";
|
|
35
|
+
}>;
|
|
36
|
+
basis: z.ZodEnum<{
|
|
37
|
+
supplied: "supplied";
|
|
38
|
+
consumed: "consumed";
|
|
39
|
+
}>;
|
|
40
|
+
promisedAmount: z.ZodString;
|
|
41
|
+
deliveredAmount: z.ZodString;
|
|
42
|
+
period: z.ZodObject<{
|
|
43
|
+
start: z.ZodString;
|
|
44
|
+
end: z.ZodString;
|
|
45
|
+
}, z.core.$strict>;
|
|
46
|
+
method: z.ZodObject<{
|
|
47
|
+
attribution: z.ZodEnum<{
|
|
48
|
+
buyer: "buyer";
|
|
49
|
+
seller: "seller";
|
|
50
|
+
"third-party": "third-party";
|
|
51
|
+
undisclosed: "undisclosed";
|
|
52
|
+
}>;
|
|
53
|
+
instrument: z.ZodString;
|
|
54
|
+
readingsHash: z.ZodOptional<z.ZodString>;
|
|
55
|
+
}, z.core.$strict>;
|
|
56
|
+
}, z.core.$strict>>;
|
|
57
|
+
externalRefs: z.ZodOptional<z.ZodObject<{
|
|
58
|
+
sellerAgentRef: z.ZodOptional<z.ZodString>;
|
|
59
|
+
buyerAgentRef: z.ZodOptional<z.ZodString>;
|
|
60
|
+
mandateRef: z.ZodOptional<z.ZodString>;
|
|
61
|
+
mandateIssuerDid: z.ZodOptional<z.ZodString>;
|
|
62
|
+
intentRef: z.ZodOptional<z.ZodString>;
|
|
63
|
+
disputeContext: z.ZodOptional<z.ZodObject<{
|
|
64
|
+
protocol: z.ZodString;
|
|
65
|
+
termsHash: z.ZodString;
|
|
66
|
+
resolutionRef: z.ZodOptional<z.ZodString>;
|
|
67
|
+
}, z.core.$strict>>;
|
|
68
|
+
}, z.core.$strict>>;
|
|
69
|
+
priorClaimId: z.ZodOptional<z.ZodString>;
|
|
70
|
+
claimId: z.ZodString;
|
|
71
|
+
signature: z.ZodString;
|
|
72
|
+
}, z.core.$strip>;
|
|
73
|
+
feedbackURI: z.ZodOptional<z.ZodString>;
|
|
74
|
+
feedbackHash: z.ZodOptional<z.ZodString>;
|
|
75
|
+
}, z.core.$strip>;
|
|
76
|
+
export type PublishReputationFeedbackInput = z.infer<typeof PublishReputationFeedbackInputSchema>;
|
|
77
|
+
export type PublishReputationFeedbackResult = {
|
|
78
|
+
ok: true;
|
|
79
|
+
chainId: string;
|
|
80
|
+
registryAddress: string;
|
|
81
|
+
agentId: string;
|
|
82
|
+
txHash: string;
|
|
83
|
+
value: number;
|
|
84
|
+
valueDecimals: number;
|
|
85
|
+
} | {
|
|
86
|
+
ok: false;
|
|
87
|
+
reason: string;
|
|
88
|
+
txHash?: string;
|
|
89
|
+
};
|
|
90
|
+
/** The minimal write surface this module needs — real ethers.Contract (connected to a Signer) satisfies this shape structurally. */
|
|
91
|
+
export interface ReputationWriteContract {
|
|
92
|
+
giveFeedback(agentId: bigint, value: bigint, valueDecimals: number, tag1: string, tag2: string, endpoint: string, feedbackURI: string, feedbackHash: string): Promise<ethers.ContractTransactionResponse>;
|
|
93
|
+
}
|
|
94
|
+
/** Dependency-injection seam, same pattern as erc8004.ts's ContractFactory — tests supply a fake contract instead of a real network call. */
|
|
95
|
+
export type ReputationContractFactory = (registryAddress: string, signer: ethers.Signer) => ReputationWriteContract;
|
|
96
|
+
/**
|
|
97
|
+
* Publish the `delivered` fact of an already-signed DeliveryClaim to an
|
|
98
|
+
* ERC-8004 Reputation Registry, as feedback about the claim's seller. The
|
|
99
|
+
* caller-supplied `signer` pays gas and becomes the feedback's on-chain
|
|
100
|
+
* `clientAddress` — it does not need to be, and normally is not, the same
|
|
101
|
+
* key that signed the claim itself (same separation eas.ts's publishClaim
|
|
102
|
+
* already makes). Re-verifies the claim's own signature before writing
|
|
103
|
+
* anything on-chain, so a tampered or unsigned claim can never be mirrored
|
|
104
|
+
* as if it were genuine. Requires a funded signer; this package never
|
|
105
|
+
* bundles an RPC, a key, or gas.
|
|
106
|
+
*/
|
|
107
|
+
/** Dependency-injection seam, same pattern as contractFactory — tests supply a fake resolver instead of a real network call. */
|
|
108
|
+
export type IdentityResolver = typeof resolveAgentIdentity;
|
|
109
|
+
export declare function publishReputationFeedback(signer: ethers.Signer, input: PublishReputationFeedbackInput, contractFactory?: ReputationContractFactory, identityResolver?: IdentityResolver): Promise<PublishReputationFeedbackResult>;
|
|
110
|
+
//# sourceMappingURL=erc8004-reputation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"erc8004-reputation.d.ts","sourceRoot":"","sources":["../src/erc8004-reputation.ts"],"names":[],"mappings":"AAkDA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAyB,oBAAoB,EAAE,MAAM,cAAc,CAAC;AA2B3E,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkB/C,CAAC;AACH,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAElG,MAAM,MAAM,+BAA+B,GACvC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAM7H;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAwBnD,oIAAoI;AACpI,MAAM,WAAW,uBAAuB;IACtC,YAAY,CACV,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC;CAChD;AAED,6IAA6I;AAC7I,MAAM,MAAM,yBAAyB,GAAG,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,KAAK,uBAAuB,CAAC;AAMpH;;;;;;;;;;GAUG;AACH,gIAAgI;AAChI,MAAM,MAAM,gBAAgB,GAAG,OAAO,oBAAoB,CAAC;AAE3D,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,CAAC,MAAM,EACrB,KAAK,EAAE,8BAA8B,EACrC,eAAe,GAAE,yBAA4D,EAC7E,gBAAgB,GAAE,gBAAuC,GACxD,OAAO,CAAC,+BAA+B,CAAC,CAiG1C"}
|