@proofchain/sdk 1.2.0 → 2.0.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 +254 -114
- package/dist/index.d.mts +2501 -276
- package/dist/index.d.ts +2501 -276
- package/dist/index.js +2031 -275
- package/dist/index.mjs +2004 -271
- package/package.json +43 -19
- package/src/client.ts +0 -312
- package/src/contract.ts +0 -212
- package/src/index.ts +0 -65
- package/src/types.ts +0 -228
- package/tsconfig.json +0 -18
package/package.json
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proofchain/sdk",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "TypeScript SDK for
|
|
5
|
-
"repository": {
|
|
6
|
-
"type": "git",
|
|
7
|
-
"url": "https://github.com/clivewatts/attestify.git"
|
|
8
|
-
},
|
|
9
|
-
"homepage": "https://proofchain.co.za",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Official JavaScript/TypeScript SDK for ProofChain - blockchain-anchored document attestation",
|
|
10
5
|
"main": "dist/index.js",
|
|
11
6
|
"module": "dist/index.mjs",
|
|
12
7
|
"types": "dist/index.d.ts",
|
|
@@ -17,32 +12,61 @@
|
|
|
17
12
|
"types": "./dist/index.d.ts"
|
|
18
13
|
}
|
|
19
14
|
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
21
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
22
22
|
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
23
|
-
"test": "vitest",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
24
25
|
"lint": "eslint src --ext .ts",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
25
27
|
"prepublishOnly": "npm run build"
|
|
26
28
|
},
|
|
27
29
|
"keywords": [
|
|
30
|
+
"proofchain",
|
|
31
|
+
"blockchain",
|
|
28
32
|
"attestation",
|
|
29
|
-
"merkle",
|
|
30
33
|
"ipfs",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
34
|
+
"proof",
|
|
35
|
+
"verification",
|
|
36
|
+
"documents",
|
|
37
|
+
"certificates",
|
|
38
|
+
"web3"
|
|
33
39
|
],
|
|
34
|
-
"author": "
|
|
35
|
-
"license": "
|
|
36
|
-
"
|
|
37
|
-
"
|
|
40
|
+
"author": "ProofChain <support@proofchain.co.za>",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/proofchain/proofchain-js.git"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://proofchain.co.za",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/proofchain/proofchain-js/issues"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=16.0.0"
|
|
38
52
|
},
|
|
39
53
|
"devDependencies": {
|
|
40
54
|
"@types/node": "^20.10.0",
|
|
55
|
+
"eslint": "^8.55.0",
|
|
41
56
|
"tsup": "^8.0.1",
|
|
42
|
-
"typescript": "^5.3.
|
|
43
|
-
"vitest": "^1.
|
|
57
|
+
"typescript": "^5.3.0",
|
|
58
|
+
"vitest": "^1.0.0"
|
|
44
59
|
},
|
|
45
60
|
"peerDependencies": {
|
|
46
|
-
"
|
|
61
|
+
"typescript": ">=4.7.0"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"typescript": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"publishConfig": {
|
|
69
|
+
"access": "public",
|
|
70
|
+
"registry": "https://registry.npmjs.org/"
|
|
47
71
|
}
|
|
48
72
|
}
|
package/src/client.ts
DELETED
|
@@ -1,312 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AttestationClientConfig,
|
|
3
|
-
RequestOptions,
|
|
4
|
-
HealthResponse,
|
|
5
|
-
ChallengeRequest,
|
|
6
|
-
ChallengeResponse,
|
|
7
|
-
VerifyRequest,
|
|
8
|
-
AuthResponse,
|
|
9
|
-
EventCreate,
|
|
10
|
-
Event,
|
|
11
|
-
EventsListResponse,
|
|
12
|
-
EventQuery,
|
|
13
|
-
MerkleTree,
|
|
14
|
-
MerkleProof,
|
|
15
|
-
VerifyProofRequest,
|
|
16
|
-
VerifyProofResponse,
|
|
17
|
-
LinkWalletRequest,
|
|
18
|
-
Wallet,
|
|
19
|
-
WalletStatus,
|
|
20
|
-
Quest,
|
|
21
|
-
QuestWithProgress,
|
|
22
|
-
UserQuestProgress,
|
|
23
|
-
QuestStepCompletionResult,
|
|
24
|
-
} from './types';
|
|
25
|
-
|
|
26
|
-
export class AttestationClientError extends Error {
|
|
27
|
-
constructor(
|
|
28
|
-
message: string,
|
|
29
|
-
public status: number,
|
|
30
|
-
public body?: unknown
|
|
31
|
-
) {
|
|
32
|
-
super(message);
|
|
33
|
-
this.name = 'AttestationClientError';
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export class AttestationClient {
|
|
38
|
-
private baseUrl: string;
|
|
39
|
-
private accessToken?: string;
|
|
40
|
-
private timeout: number;
|
|
41
|
-
|
|
42
|
-
constructor(config: AttestationClientConfig) {
|
|
43
|
-
this.baseUrl = config.baseUrl.replace(/\/$/, '');
|
|
44
|
-
this.accessToken = config.accessToken;
|
|
45
|
-
this.timeout = config.timeout ?? 30000;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ============ Internal Methods ============
|
|
49
|
-
|
|
50
|
-
private async request<T>(
|
|
51
|
-
method: string,
|
|
52
|
-
path: string,
|
|
53
|
-
body?: unknown,
|
|
54
|
-
options?: RequestOptions
|
|
55
|
-
): Promise<T> {
|
|
56
|
-
const url = `${this.baseUrl}${path}`;
|
|
57
|
-
const controller = new AbortController();
|
|
58
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
59
|
-
|
|
60
|
-
const headers: Record<string, string> = {
|
|
61
|
-
'Content-Type': 'application/json',
|
|
62
|
-
...options?.headers,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
if (this.accessToken) {
|
|
66
|
-
headers['Authorization'] = `Bearer ${this.accessToken}`;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
const response = await fetch(url, {
|
|
71
|
-
method,
|
|
72
|
-
headers,
|
|
73
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
74
|
-
signal: options?.signal ?? controller.signal,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
clearTimeout(timeoutId);
|
|
78
|
-
|
|
79
|
-
if (!response.ok) {
|
|
80
|
-
const errorBody = await response.json().catch(() => null);
|
|
81
|
-
throw new AttestationClientError(
|
|
82
|
-
`Request failed: ${response.status} ${response.statusText}`,
|
|
83
|
-
response.status,
|
|
84
|
-
errorBody
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return response.json();
|
|
89
|
-
} catch (error) {
|
|
90
|
-
clearTimeout(timeoutId);
|
|
91
|
-
if (error instanceof AttestationClientError) throw error;
|
|
92
|
-
throw new AttestationClientError(
|
|
93
|
-
`Request failed: ${(error as Error).message}`,
|
|
94
|
-
0
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ============ Auth Methods ============
|
|
100
|
-
|
|
101
|
-
setAccessToken(token: string): void {
|
|
102
|
-
this.accessToken = token;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
clearAccessToken(): void {
|
|
106
|
-
this.accessToken = undefined;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ============ Health ============
|
|
110
|
-
|
|
111
|
-
async health(): Promise<HealthResponse> {
|
|
112
|
-
return this.request<HealthResponse>('GET', '/health');
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// ============ Authentication ============
|
|
116
|
-
|
|
117
|
-
async requestChallenge(walletAddress: string): Promise<ChallengeResponse> {
|
|
118
|
-
return this.request<ChallengeResponse>('POST', '/auth/web3/challenge', {
|
|
119
|
-
wallet_address: walletAddress,
|
|
120
|
-
} as ChallengeRequest);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async verifySignature(
|
|
124
|
-
walletAddress: string,
|
|
125
|
-
signature: string,
|
|
126
|
-
message: string
|
|
127
|
-
): Promise<AuthResponse> {
|
|
128
|
-
const response = await this.request<AuthResponse>('POST', '/auth/web3/verify', {
|
|
129
|
-
wallet_address: walletAddress,
|
|
130
|
-
signature,
|
|
131
|
-
message,
|
|
132
|
-
} as VerifyRequest);
|
|
133
|
-
|
|
134
|
-
// Auto-set the access token
|
|
135
|
-
if (response.access_token) {
|
|
136
|
-
this.setAccessToken(response.access_token);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return response;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// ============ Events ============
|
|
143
|
-
|
|
144
|
-
async createEvent(event: EventCreate): Promise<Event> {
|
|
145
|
-
return this.request<Event>('POST', '/events', event);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async getEvents(
|
|
149
|
-
userId: string,
|
|
150
|
-
options?: {
|
|
151
|
-
limit?: number;
|
|
152
|
-
offset?: number;
|
|
153
|
-
eventType?: string;
|
|
154
|
-
fetchData?: boolean;
|
|
155
|
-
}
|
|
156
|
-
): Promise<EventsListResponse> {
|
|
157
|
-
const params = new URLSearchParams();
|
|
158
|
-
if (options?.limit) params.set('limit', options.limit.toString());
|
|
159
|
-
if (options?.offset) params.set('offset', options.offset.toString());
|
|
160
|
-
if (options?.eventType) params.set('event_type', options.eventType);
|
|
161
|
-
if (options?.fetchData) params.set('fetch_data', 'true');
|
|
162
|
-
|
|
163
|
-
const query = params.toString();
|
|
164
|
-
return this.request<EventsListResponse>(
|
|
165
|
-
'GET',
|
|
166
|
-
`/data/events/${userId}${query ? `?${query}` : ''}`
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async queryEvents(userId: string, query: EventQuery): Promise<EventsListResponse> {
|
|
171
|
-
return this.request<EventsListResponse>(
|
|
172
|
-
'POST',
|
|
173
|
-
`/data/events/${userId}/query`,
|
|
174
|
-
query
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// ============ Merkle Tree ============
|
|
179
|
-
|
|
180
|
-
async rebuildMerkleTree(userId: string): Promise<MerkleTree> {
|
|
181
|
-
return this.request<MerkleTree>('POST', `/merkle/rebuild/${userId}`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
async getMerkleRoot(userId: string): Promise<MerkleTree> {
|
|
185
|
-
return this.request<MerkleTree>('GET', `/merkle/root/${userId}`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async getMerkleProof(userId: string, ipfsHash: string): Promise<MerkleProof> {
|
|
189
|
-
return this.request<MerkleProof>('GET', `/merkle/proof/${userId}/${ipfsHash}`);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
async verifyMerkleProof(
|
|
193
|
-
leaf: string,
|
|
194
|
-
proof: string[],
|
|
195
|
-
root: string
|
|
196
|
-
): Promise<VerifyProofResponse> {
|
|
197
|
-
return this.request<VerifyProofResponse>('POST', '/merkle/verify', {
|
|
198
|
-
leaf,
|
|
199
|
-
proof,
|
|
200
|
-
root,
|
|
201
|
-
} as VerifyProofRequest);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// ============ Wallets ============
|
|
205
|
-
|
|
206
|
-
async linkWallet(request: LinkWalletRequest): Promise<Wallet> {
|
|
207
|
-
return this.request<Wallet>('POST', '/wallet/link', request);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async getWalletStatus(userId: string): Promise<WalletStatus> {
|
|
211
|
-
return this.request<WalletStatus>('GET', `/wallet/status/${userId}`);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// ============ Quests ============
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* List available quests for a user
|
|
218
|
-
* @param userId - End user external ID
|
|
219
|
-
* @param options - Filter options
|
|
220
|
-
*/
|
|
221
|
-
async getAvailableQuests(
|
|
222
|
-
userId: string,
|
|
223
|
-
options?: { category?: string; limit?: number }
|
|
224
|
-
): Promise<QuestWithProgress[]> {
|
|
225
|
-
const params = new URLSearchParams();
|
|
226
|
-
params.set('user_id', userId);
|
|
227
|
-
if (options?.category) params.set('category', options.category);
|
|
228
|
-
if (options?.limit) params.set('limit', options.limit.toString());
|
|
229
|
-
|
|
230
|
-
return this.request<QuestWithProgress[]>(
|
|
231
|
-
'GET',
|
|
232
|
-
`/quests/available?${params.toString()}`
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Get a specific quest by ID with all steps
|
|
238
|
-
* @param questId - Quest ID
|
|
239
|
-
*/
|
|
240
|
-
async getQuest(questId: string): Promise<Quest> {
|
|
241
|
-
return this.request<Quest>('GET', `/quests/${questId}`);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Start a quest for a user
|
|
246
|
-
* @param questId - Quest ID
|
|
247
|
-
* @param userId - End user external ID
|
|
248
|
-
*/
|
|
249
|
-
async startQuest(questId: string, userId: string): Promise<UserQuestProgress> {
|
|
250
|
-
return this.request<UserQuestProgress>(
|
|
251
|
-
'POST',
|
|
252
|
-
`/quests/${questId}/start?user_id=${encodeURIComponent(userId)}`,
|
|
253
|
-
{}
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Get user's progress on a specific quest
|
|
259
|
-
* @param questId - Quest ID
|
|
260
|
-
* @param userId - End user external ID
|
|
261
|
-
*/
|
|
262
|
-
async getQuestProgress(questId: string, userId: string): Promise<UserQuestProgress> {
|
|
263
|
-
return this.request<UserQuestProgress>(
|
|
264
|
-
'GET',
|
|
265
|
-
`/quests/${questId}/progress/${encodeURIComponent(userId)}`
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Get all quest progress for a user
|
|
271
|
-
* @param userId - End user external ID
|
|
272
|
-
* @param status - Optional status filter
|
|
273
|
-
*/
|
|
274
|
-
async getUserQuestProgress(
|
|
275
|
-
userId: string,
|
|
276
|
-
status?: string
|
|
277
|
-
): Promise<UserQuestProgress[]> {
|
|
278
|
-
const params = new URLSearchParams();
|
|
279
|
-
if (status) params.set('status', status);
|
|
280
|
-
const query = params.toString();
|
|
281
|
-
|
|
282
|
-
return this.request<UserQuestProgress[]>(
|
|
283
|
-
'GET',
|
|
284
|
-
`/quests/user/${encodeURIComponent(userId)}/progress${query ? `?${query}` : ''}`
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Complete or increment a quest step
|
|
290
|
-
* @param questId - Quest ID
|
|
291
|
-
* @param userId - End user external ID
|
|
292
|
-
* @param stepIndex - Step index (0-based)
|
|
293
|
-
* @param options - Completion options
|
|
294
|
-
*/
|
|
295
|
-
async completeQuestStep(
|
|
296
|
-
questId: string,
|
|
297
|
-
userId: string,
|
|
298
|
-
stepIndex: number,
|
|
299
|
-
options?: { count?: number; value?: string }
|
|
300
|
-
): Promise<QuestStepCompletionResult> {
|
|
301
|
-
const params = new URLSearchParams();
|
|
302
|
-
if (options?.count) params.set('count', options.count.toString());
|
|
303
|
-
if (options?.value) params.set('value', options.value);
|
|
304
|
-
const query = params.toString();
|
|
305
|
-
|
|
306
|
-
return this.request<QuestStepCompletionResult>(
|
|
307
|
-
'POST',
|
|
308
|
-
`/quests/${questId}/progress/${encodeURIComponent(userId)}/step/${stepIndex}/complete${query ? `?${query}` : ''}`,
|
|
309
|
-
{}
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
}
|
package/src/contract.ts
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import { ethers, type Signer, type Provider, type ContractTransactionResponse } from 'ethers';
|
|
2
|
-
|
|
3
|
-
// ABI for AttestationRegistry contract
|
|
4
|
-
const ATTESTATION_REGISTRY_ABI = [
|
|
5
|
-
// Read functions
|
|
6
|
-
'function attestationRoots(address wallet) view returns (bytes32 merkleRoot, uint256 eventCount, uint256 lastUpdated, string latestIpfsHash)',
|
|
7
|
-
'function getRoot(address wallet) view returns (bytes32 root, uint256 eventCount, uint256 lastUpdated, string latestIpfsHash)',
|
|
8
|
-
'function getHistoryCount(address wallet) view returns (uint256 count)',
|
|
9
|
-
'function getHistoricalRoot(address wallet, uint256 index) view returns (bytes32 root, uint256 eventCount, uint256 timestamp)',
|
|
10
|
-
'function verifyAttestation(address wallet, bytes32 leaf, bytes32[] proof) view returns (bool valid)',
|
|
11
|
-
'function computeLeaf(string ipfsHash, string eventType, uint256 timestamp) pure returns (bytes32 leaf)',
|
|
12
|
-
'function getWalletByIpfsHash(string ipfsHash) view returns (address wallet)',
|
|
13
|
-
'function authorizedUpdaters(address) view returns (bool)',
|
|
14
|
-
'function owner() view returns (address)',
|
|
15
|
-
|
|
16
|
-
// Write functions
|
|
17
|
-
'function updateRoot(address wallet, bytes32 newRoot, uint256 eventCount, string latestIpfsHash)',
|
|
18
|
-
'function batchUpdateRoots(address[] wallets, bytes32[] roots, uint256[] eventCounts, string[] ipfsHashes)',
|
|
19
|
-
'function setAuthorizedUpdater(address updater, bool authorized)',
|
|
20
|
-
|
|
21
|
-
// Events
|
|
22
|
-
'event RootUpdated(address indexed wallet, bytes32 indexed newRoot, bytes32 indexed previousRoot, uint256 eventCount, string latestIpfsHash)',
|
|
23
|
-
'event AttestationVerified(address indexed wallet, bytes32 indexed leaf, string ipfsHash, bool valid)',
|
|
24
|
-
'event UpdaterAuthorized(address indexed updater, bool authorized)',
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
export interface AttestationRoot {
|
|
28
|
-
merkleRoot: string;
|
|
29
|
-
eventCount: bigint;
|
|
30
|
-
lastUpdated: bigint;
|
|
31
|
-
latestIpfsHash: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface RootHistory {
|
|
35
|
-
merkleRoot: string;
|
|
36
|
-
eventCount: bigint;
|
|
37
|
-
timestamp: bigint;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface RootUpdatedEvent {
|
|
41
|
-
wallet: string;
|
|
42
|
-
newRoot: string;
|
|
43
|
-
previousRoot: string;
|
|
44
|
-
eventCount: bigint;
|
|
45
|
-
latestIpfsHash: string;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export class AttestationRegistryContract {
|
|
49
|
-
private contract: ethers.Contract;
|
|
50
|
-
private signer?: Signer;
|
|
51
|
-
|
|
52
|
-
constructor(
|
|
53
|
-
contractAddress: string,
|
|
54
|
-
signerOrProvider: Signer | Provider
|
|
55
|
-
) {
|
|
56
|
-
this.contract = new ethers.Contract(
|
|
57
|
-
contractAddress,
|
|
58
|
-
ATTESTATION_REGISTRY_ABI,
|
|
59
|
-
signerOrProvider
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
if ('getAddress' in signerOrProvider) {
|
|
63
|
-
this.signer = signerOrProvider as Signer;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// ============ Read Functions ============
|
|
68
|
-
|
|
69
|
-
async getRoot(wallet: string): Promise<AttestationRoot> {
|
|
70
|
-
const [merkleRoot, eventCount, lastUpdated, latestIpfsHash] =
|
|
71
|
-
await this.contract.getRoot(wallet);
|
|
72
|
-
return {
|
|
73
|
-
merkleRoot,
|
|
74
|
-
eventCount,
|
|
75
|
-
lastUpdated,
|
|
76
|
-
latestIpfsHash,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async getHistoryCount(wallet: string): Promise<bigint> {
|
|
81
|
-
return this.contract.getHistoryCount(wallet);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async getHistoricalRoot(wallet: string, index: number): Promise<RootHistory> {
|
|
85
|
-
const [merkleRoot, eventCount, timestamp] =
|
|
86
|
-
await this.contract.getHistoricalRoot(wallet, index);
|
|
87
|
-
return { merkleRoot, eventCount, timestamp };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async verifyAttestation(
|
|
91
|
-
wallet: string,
|
|
92
|
-
leaf: string,
|
|
93
|
-
proof: string[]
|
|
94
|
-
): Promise<boolean> {
|
|
95
|
-
return this.contract.verifyAttestation(wallet, leaf, proof);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async computeLeaf(
|
|
99
|
-
ipfsHash: string,
|
|
100
|
-
eventType: string,
|
|
101
|
-
timestamp: number
|
|
102
|
-
): Promise<string> {
|
|
103
|
-
return this.contract.computeLeaf(ipfsHash, eventType, timestamp);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async getWalletByIpfsHash(ipfsHash: string): Promise<string> {
|
|
107
|
-
return this.contract.getWalletByIpfsHash(ipfsHash);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async isAuthorizedUpdater(address: string): Promise<boolean> {
|
|
111
|
-
return this.contract.authorizedUpdaters(address);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async owner(): Promise<string> {
|
|
115
|
-
return this.contract.owner();
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// ============ Write Functions ============
|
|
119
|
-
|
|
120
|
-
async updateRoot(
|
|
121
|
-
wallet: string,
|
|
122
|
-
newRoot: string,
|
|
123
|
-
eventCount: number,
|
|
124
|
-
latestIpfsHash: string
|
|
125
|
-
): Promise<ContractTransactionResponse> {
|
|
126
|
-
if (!this.signer) {
|
|
127
|
-
throw new Error('Signer required for write operations');
|
|
128
|
-
}
|
|
129
|
-
return this.contract.updateRoot(wallet, newRoot, eventCount, latestIpfsHash);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async batchUpdateRoots(
|
|
133
|
-
wallets: string[],
|
|
134
|
-
roots: string[],
|
|
135
|
-
eventCounts: number[],
|
|
136
|
-
ipfsHashes: string[]
|
|
137
|
-
): Promise<ContractTransactionResponse> {
|
|
138
|
-
if (!this.signer) {
|
|
139
|
-
throw new Error('Signer required for write operations');
|
|
140
|
-
}
|
|
141
|
-
return this.contract.batchUpdateRoots(wallets, roots, eventCounts, ipfsHashes);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async setAuthorizedUpdater(
|
|
145
|
-
updater: string,
|
|
146
|
-
authorized: boolean
|
|
147
|
-
): Promise<ContractTransactionResponse> {
|
|
148
|
-
if (!this.signer) {
|
|
149
|
-
throw new Error('Signer required for write operations');
|
|
150
|
-
}
|
|
151
|
-
return this.contract.setAuthorizedUpdater(updater, authorized);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// ============ Event Listeners ============
|
|
155
|
-
|
|
156
|
-
onRootUpdated(
|
|
157
|
-
callback: (event: RootUpdatedEvent) => void,
|
|
158
|
-
filter?: { wallet?: string }
|
|
159
|
-
): void {
|
|
160
|
-
const eventFilter = this.contract.filters.RootUpdated(filter?.wallet);
|
|
161
|
-
this.contract.on(eventFilter, (wallet, newRoot, previousRoot, eventCount, latestIpfsHash) => {
|
|
162
|
-
callback({
|
|
163
|
-
wallet,
|
|
164
|
-
newRoot,
|
|
165
|
-
previousRoot,
|
|
166
|
-
eventCount,
|
|
167
|
-
latestIpfsHash,
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
removeAllListeners(): void {
|
|
173
|
-
this.contract.removeAllListeners();
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// ============ Utilities ============
|
|
177
|
-
|
|
178
|
-
static computeLeafOffchain(
|
|
179
|
-
ipfsHash: string,
|
|
180
|
-
eventType: string,
|
|
181
|
-
timestamp: number
|
|
182
|
-
): string {
|
|
183
|
-
return ethers.keccak256(
|
|
184
|
-
ethers.solidityPacked(
|
|
185
|
-
['string', 'string', 'uint256'],
|
|
186
|
-
[ipfsHash, eventType, timestamp]
|
|
187
|
-
)
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
static verifyProofOffchain(
|
|
192
|
-
leaf: string,
|
|
193
|
-
proof: string[],
|
|
194
|
-
root: string
|
|
195
|
-
): boolean {
|
|
196
|
-
let computedHash = leaf;
|
|
197
|
-
|
|
198
|
-
for (const proofElement of proof) {
|
|
199
|
-
if (computedHash < proofElement) {
|
|
200
|
-
computedHash = ethers.keccak256(
|
|
201
|
-
ethers.solidityPacked(['bytes32', 'bytes32'], [computedHash, proofElement])
|
|
202
|
-
);
|
|
203
|
-
} else {
|
|
204
|
-
computedHash = ethers.keccak256(
|
|
205
|
-
ethers.solidityPacked(['bytes32', 'bytes32'], [proofElement, computedHash])
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return computedHash === root;
|
|
211
|
-
}
|
|
212
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2024-2025 Clive Watts / MegaWatts Solutions
|
|
3
|
-
* All Rights Reserved.
|
|
4
|
-
*
|
|
5
|
-
* PROPRIETARY AND CONFIDENTIAL
|
|
6
|
-
* This software is the exclusive property of MegaWatts Solutions.
|
|
7
|
-
* Unauthorized copying, distribution, or use is strictly prohibited.
|
|
8
|
-
* See LICENSE file for full terms.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
// Client
|
|
12
|
-
export { AttestationClient, AttestationClientError } from './client';
|
|
13
|
-
|
|
14
|
-
// Contract
|
|
15
|
-
export {
|
|
16
|
-
AttestationRegistryContract,
|
|
17
|
-
type AttestationRoot,
|
|
18
|
-
type RootHistory,
|
|
19
|
-
type RootUpdatedEvent,
|
|
20
|
-
} from './contract';
|
|
21
|
-
|
|
22
|
-
// Types
|
|
23
|
-
export type {
|
|
24
|
-
// Config
|
|
25
|
-
AttestationClientConfig,
|
|
26
|
-
RequestOptions,
|
|
27
|
-
|
|
28
|
-
// Requests
|
|
29
|
-
ChallengeRequest,
|
|
30
|
-
VerifyRequest,
|
|
31
|
-
EventCreate,
|
|
32
|
-
EventQuery,
|
|
33
|
-
VerifyProofRequest,
|
|
34
|
-
LinkWalletRequest,
|
|
35
|
-
|
|
36
|
-
// Responses
|
|
37
|
-
HealthResponse,
|
|
38
|
-
ChallengeResponse,
|
|
39
|
-
AuthResponse,
|
|
40
|
-
Event,
|
|
41
|
-
EventsListResponse,
|
|
42
|
-
MerkleTree,
|
|
43
|
-
MerkleProof,
|
|
44
|
-
VerifyProofResponse,
|
|
45
|
-
Wallet,
|
|
46
|
-
WalletStatus,
|
|
47
|
-
|
|
48
|
-
// Quests
|
|
49
|
-
Quest,
|
|
50
|
-
QuestStep,
|
|
51
|
-
QuestWithProgress,
|
|
52
|
-
UserQuestProgress,
|
|
53
|
-
QuestStepCompletionResult,
|
|
54
|
-
RewardInfo,
|
|
55
|
-
} from './types';
|
|
56
|
-
|
|
57
|
-
// Convenience factory
|
|
58
|
-
import { AttestationClient as Client } from './client';
|
|
59
|
-
|
|
60
|
-
export function createClient(baseUrl: string, accessToken?: string): Client {
|
|
61
|
-
return new Client({
|
|
62
|
-
baseUrl,
|
|
63
|
-
accessToken,
|
|
64
|
-
});
|
|
65
|
-
}
|