@thurinlabs/identity-kit 0.8.0 → 1.0.1

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/dist/index.js CHANGED
@@ -1,13 +1,1248 @@
1
1
  // src/provider.tsx
2
2
  import { useMemo } from "react";
3
3
  import { WagmiProvider, createConfig, http, useConfig } from "wagmi";
4
- import { mainnet } from "wagmi/chains";
4
+ import { mainnet, sepolia, foundry } from "wagmi/chains";
5
+
6
+ // src/core/abi.ts
7
+ var REGISTRY_ABI = [
8
+ {
9
+ "type": "function",
10
+ "name": "ATTEST_TYPEHASH",
11
+ "inputs": [],
12
+ "outputs": [
13
+ {
14
+ "name": "",
15
+ "type": "bytes32",
16
+ "internalType": "bytes32"
17
+ }
18
+ ],
19
+ "stateMutability": "view"
20
+ },
21
+ {
22
+ "type": "function",
23
+ "name": "DOMAIN_SEPARATOR",
24
+ "inputs": [],
25
+ "outputs": [
26
+ {
27
+ "name": "",
28
+ "type": "bytes32",
29
+ "internalType": "bytes32"
30
+ }
31
+ ],
32
+ "stateMutability": "view"
33
+ },
34
+ {
35
+ "type": "function",
36
+ "name": "EIP712_NAME",
37
+ "inputs": [],
38
+ "outputs": [
39
+ {
40
+ "name": "",
41
+ "type": "string",
42
+ "internalType": "string"
43
+ }
44
+ ],
45
+ "stateMutability": "view"
46
+ },
47
+ {
48
+ "type": "function",
49
+ "name": "EIP712_VERSION",
50
+ "inputs": [],
51
+ "outputs": [
52
+ {
53
+ "name": "",
54
+ "type": "string",
55
+ "internalType": "string"
56
+ }
57
+ ],
58
+ "stateMutability": "view"
59
+ },
60
+ {
61
+ "type": "function",
62
+ "name": "MAX_KEY_BYTES",
63
+ "inputs": [],
64
+ "outputs": [
65
+ {
66
+ "name": "",
67
+ "type": "uint256",
68
+ "internalType": "uint256"
69
+ }
70
+ ],
71
+ "stateMutability": "view"
72
+ },
73
+ {
74
+ "type": "function",
75
+ "name": "MAX_RECORD_BYTES",
76
+ "inputs": [],
77
+ "outputs": [
78
+ {
79
+ "name": "",
80
+ "type": "uint256",
81
+ "internalType": "uint256"
82
+ }
83
+ ],
84
+ "stateMutability": "view"
85
+ },
86
+ {
87
+ "type": "function",
88
+ "name": "MAX_SIG_BYTES",
89
+ "inputs": [],
90
+ "outputs": [
91
+ {
92
+ "name": "",
93
+ "type": "uint256",
94
+ "internalType": "uint256"
95
+ }
96
+ ],
97
+ "stateMutability": "view"
98
+ },
99
+ {
100
+ "type": "function",
101
+ "name": "MESSAGE_VERSION",
102
+ "inputs": [],
103
+ "outputs": [
104
+ {
105
+ "name": "",
106
+ "type": "uint8",
107
+ "internalType": "uint8"
108
+ }
109
+ ],
110
+ "stateMutability": "view"
111
+ },
112
+ {
113
+ "type": "function",
114
+ "name": "REATTEST_TYPEHASH",
115
+ "inputs": [],
116
+ "outputs": [
117
+ {
118
+ "name": "",
119
+ "type": "bytes32",
120
+ "internalType": "bytes32"
121
+ }
122
+ ],
123
+ "stateMutability": "view"
124
+ },
125
+ {
126
+ "type": "function",
127
+ "name": "REVOKE_TYPEHASH",
128
+ "inputs": [],
129
+ "outputs": [
130
+ {
131
+ "name": "",
132
+ "type": "bytes32",
133
+ "internalType": "bytes32"
134
+ }
135
+ ],
136
+ "stateMutability": "view"
137
+ },
138
+ {
139
+ "type": "function",
140
+ "name": "SET_RECORD_TYPEHASH",
141
+ "inputs": [],
142
+ "outputs": [
143
+ {
144
+ "name": "",
145
+ "type": "bytes32",
146
+ "internalType": "bytes32"
147
+ }
148
+ ],
149
+ "stateMutability": "view"
150
+ },
151
+ {
152
+ "type": "function",
153
+ "name": "UPDATE_KEY_TYPEHASH",
154
+ "inputs": [],
155
+ "outputs": [
156
+ {
157
+ "name": "",
158
+ "type": "bytes32",
159
+ "internalType": "bytes32"
160
+ }
161
+ ],
162
+ "stateMutability": "view"
163
+ },
164
+ {
165
+ "type": "function",
166
+ "name": "VERSION",
167
+ "inputs": [],
168
+ "outputs": [
169
+ {
170
+ "name": "",
171
+ "type": "uint8",
172
+ "internalType": "uint8"
173
+ }
174
+ ],
175
+ "stateMutability": "view"
176
+ },
177
+ {
178
+ "type": "function",
179
+ "name": "addressesFor",
180
+ "inputs": [
181
+ {
182
+ "name": "fingerprintHash",
183
+ "type": "bytes32",
184
+ "internalType": "bytes32"
185
+ }
186
+ ],
187
+ "outputs": [
188
+ {
189
+ "name": "",
190
+ "type": "address[]",
191
+ "internalType": "address[]"
192
+ }
193
+ ],
194
+ "stateMutability": "view"
195
+ },
196
+ {
197
+ "type": "function",
198
+ "name": "addressesForCount",
199
+ "inputs": [
200
+ {
201
+ "name": "fingerprintHash",
202
+ "type": "bytes32",
203
+ "internalType": "bytes32"
204
+ }
205
+ ],
206
+ "outputs": [
207
+ {
208
+ "name": "",
209
+ "type": "uint256",
210
+ "internalType": "uint256"
211
+ }
212
+ ],
213
+ "stateMutability": "view"
214
+ },
215
+ {
216
+ "type": "function",
217
+ "name": "addressesForRange",
218
+ "inputs": [
219
+ {
220
+ "name": "fingerprintHash",
221
+ "type": "bytes32",
222
+ "internalType": "bytes32"
223
+ },
224
+ {
225
+ "name": "start",
226
+ "type": "uint256",
227
+ "internalType": "uint256"
228
+ },
229
+ {
230
+ "name": "count",
231
+ "type": "uint256",
232
+ "internalType": "uint256"
233
+ }
234
+ ],
235
+ "outputs": [
236
+ {
237
+ "name": "out",
238
+ "type": "address[]",
239
+ "internalType": "address[]"
240
+ }
241
+ ],
242
+ "stateMutability": "view"
243
+ },
244
+ {
245
+ "type": "function",
246
+ "name": "attest",
247
+ "inputs": [
248
+ {
249
+ "name": "fingerprint",
250
+ "type": "bytes",
251
+ "internalType": "bytes"
252
+ },
253
+ {
254
+ "name": "pgpSignature",
255
+ "type": "bytes",
256
+ "internalType": "bytes"
257
+ },
258
+ {
259
+ "name": "pgpPublicKey",
260
+ "type": "bytes",
261
+ "internalType": "bytes"
262
+ }
263
+ ],
264
+ "outputs": [
265
+ {
266
+ "name": "index",
267
+ "type": "uint256",
268
+ "internalType": "uint256"
269
+ }
270
+ ],
271
+ "stateMutability": "nonpayable"
272
+ },
273
+ {
274
+ "type": "function",
275
+ "name": "attestFor",
276
+ "inputs": [
277
+ {
278
+ "name": "owner",
279
+ "type": "address",
280
+ "internalType": "address"
281
+ },
282
+ {
283
+ "name": "fingerprint",
284
+ "type": "bytes",
285
+ "internalType": "bytes"
286
+ },
287
+ {
288
+ "name": "pgpSignature",
289
+ "type": "bytes",
290
+ "internalType": "bytes"
291
+ },
292
+ {
293
+ "name": "pgpPublicKey",
294
+ "type": "bytes",
295
+ "internalType": "bytes"
296
+ },
297
+ {
298
+ "name": "deadline",
299
+ "type": "uint256",
300
+ "internalType": "uint256"
301
+ },
302
+ {
303
+ "name": "signature",
304
+ "type": "bytes",
305
+ "internalType": "bytes"
306
+ }
307
+ ],
308
+ "outputs": [
309
+ {
310
+ "name": "index",
311
+ "type": "uint256",
312
+ "internalType": "uint256"
313
+ }
314
+ ],
315
+ "stateMutability": "nonpayable"
316
+ },
317
+ {
318
+ "type": "function",
319
+ "name": "attestationCount",
320
+ "inputs": [
321
+ {
322
+ "name": "owner",
323
+ "type": "address",
324
+ "internalType": "address"
325
+ }
326
+ ],
327
+ "outputs": [
328
+ {
329
+ "name": "",
330
+ "type": "uint256",
331
+ "internalType": "uint256"
332
+ }
333
+ ],
334
+ "stateMutability": "view"
335
+ },
336
+ {
337
+ "type": "function",
338
+ "name": "attestationsOf",
339
+ "inputs": [
340
+ {
341
+ "name": "owner",
342
+ "type": "address",
343
+ "internalType": "address"
344
+ }
345
+ ],
346
+ "outputs": [
347
+ {
348
+ "name": "",
349
+ "type": "tuple[]",
350
+ "internalType": "struct PGPRegistry.Attestation[]",
351
+ "components": [
352
+ {
353
+ "name": "fingerprint",
354
+ "type": "bytes",
355
+ "internalType": "bytes"
356
+ },
357
+ {
358
+ "name": "createdAt",
359
+ "type": "uint64",
360
+ "internalType": "uint64"
361
+ },
362
+ {
363
+ "name": "revokedAt",
364
+ "type": "uint64",
365
+ "internalType": "uint64"
366
+ },
367
+ {
368
+ "name": "messageVersion",
369
+ "type": "uint8",
370
+ "internalType": "uint8"
371
+ },
372
+ {
373
+ "name": "keyPtr",
374
+ "type": "address",
375
+ "internalType": "address"
376
+ },
377
+ {
378
+ "name": "sigPtr",
379
+ "type": "address",
380
+ "internalType": "address"
381
+ }
382
+ ]
383
+ }
384
+ ],
385
+ "stateMutability": "view"
386
+ },
387
+ {
388
+ "type": "function",
389
+ "name": "attestationsOfRange",
390
+ "inputs": [
391
+ {
392
+ "name": "owner",
393
+ "type": "address",
394
+ "internalType": "address"
395
+ },
396
+ {
397
+ "name": "start",
398
+ "type": "uint256",
399
+ "internalType": "uint256"
400
+ },
401
+ {
402
+ "name": "count",
403
+ "type": "uint256",
404
+ "internalType": "uint256"
405
+ }
406
+ ],
407
+ "outputs": [
408
+ {
409
+ "name": "out",
410
+ "type": "tuple[]",
411
+ "internalType": "struct PGPRegistry.Attestation[]",
412
+ "components": [
413
+ {
414
+ "name": "fingerprint",
415
+ "type": "bytes",
416
+ "internalType": "bytes"
417
+ },
418
+ {
419
+ "name": "createdAt",
420
+ "type": "uint64",
421
+ "internalType": "uint64"
422
+ },
423
+ {
424
+ "name": "revokedAt",
425
+ "type": "uint64",
426
+ "internalType": "uint64"
427
+ },
428
+ {
429
+ "name": "messageVersion",
430
+ "type": "uint8",
431
+ "internalType": "uint8"
432
+ },
433
+ {
434
+ "name": "keyPtr",
435
+ "type": "address",
436
+ "internalType": "address"
437
+ },
438
+ {
439
+ "name": "sigPtr",
440
+ "type": "address",
441
+ "internalType": "address"
442
+ }
443
+ ]
444
+ }
445
+ ],
446
+ "stateMutability": "view"
447
+ },
448
+ {
449
+ "type": "function",
450
+ "name": "cancelAuthorization",
451
+ "inputs": [],
452
+ "outputs": [],
453
+ "stateMutability": "nonpayable"
454
+ },
455
+ {
456
+ "type": "function",
457
+ "name": "current",
458
+ "inputs": [
459
+ {
460
+ "name": "owner",
461
+ "type": "address",
462
+ "internalType": "address"
463
+ }
464
+ ],
465
+ "outputs": [
466
+ {
467
+ "name": "found",
468
+ "type": "bool",
469
+ "internalType": "bool"
470
+ },
471
+ {
472
+ "name": "index",
473
+ "type": "uint256",
474
+ "internalType": "uint256"
475
+ },
476
+ {
477
+ "name": "attestation",
478
+ "type": "tuple",
479
+ "internalType": "struct PGPRegistry.Attestation",
480
+ "components": [
481
+ {
482
+ "name": "fingerprint",
483
+ "type": "bytes",
484
+ "internalType": "bytes"
485
+ },
486
+ {
487
+ "name": "createdAt",
488
+ "type": "uint64",
489
+ "internalType": "uint64"
490
+ },
491
+ {
492
+ "name": "revokedAt",
493
+ "type": "uint64",
494
+ "internalType": "uint64"
495
+ },
496
+ {
497
+ "name": "messageVersion",
498
+ "type": "uint8",
499
+ "internalType": "uint8"
500
+ },
501
+ {
502
+ "name": "keyPtr",
503
+ "type": "address",
504
+ "internalType": "address"
505
+ },
506
+ {
507
+ "name": "sigPtr",
508
+ "type": "address",
509
+ "internalType": "address"
510
+ }
511
+ ]
512
+ }
513
+ ],
514
+ "stateMutability": "view"
515
+ },
516
+ {
517
+ "type": "function",
518
+ "name": "fingerprintsForKeyId",
519
+ "inputs": [
520
+ {
521
+ "name": "keyId",
522
+ "type": "bytes8",
523
+ "internalType": "bytes8"
524
+ }
525
+ ],
526
+ "outputs": [
527
+ {
528
+ "name": "",
529
+ "type": "bytes[]",
530
+ "internalType": "bytes[]"
531
+ }
532
+ ],
533
+ "stateMutability": "view"
534
+ },
535
+ {
536
+ "type": "function",
537
+ "name": "fingerprintsForKeyIdCount",
538
+ "inputs": [
539
+ {
540
+ "name": "keyId",
541
+ "type": "bytes8",
542
+ "internalType": "bytes8"
543
+ }
544
+ ],
545
+ "outputs": [
546
+ {
547
+ "name": "",
548
+ "type": "uint256",
549
+ "internalType": "uint256"
550
+ }
551
+ ],
552
+ "stateMutability": "view"
553
+ },
554
+ {
555
+ "type": "function",
556
+ "name": "fingerprintsForKeyIdRange",
557
+ "inputs": [
558
+ {
559
+ "name": "keyId",
560
+ "type": "bytes8",
561
+ "internalType": "bytes8"
562
+ },
563
+ {
564
+ "name": "start",
565
+ "type": "uint256",
566
+ "internalType": "uint256"
567
+ },
568
+ {
569
+ "name": "count",
570
+ "type": "uint256",
571
+ "internalType": "uint256"
572
+ }
573
+ ],
574
+ "outputs": [
575
+ {
576
+ "name": "out",
577
+ "type": "bytes[]",
578
+ "internalType": "bytes[]"
579
+ }
580
+ ],
581
+ "stateMutability": "view"
582
+ },
583
+ {
584
+ "type": "function",
585
+ "name": "getAttestation",
586
+ "inputs": [
587
+ {
588
+ "name": "owner",
589
+ "type": "address",
590
+ "internalType": "address"
591
+ },
592
+ {
593
+ "name": "index",
594
+ "type": "uint256",
595
+ "internalType": "uint256"
596
+ }
597
+ ],
598
+ "outputs": [
599
+ {
600
+ "name": "",
601
+ "type": "tuple",
602
+ "internalType": "struct PGPRegistry.Attestation",
603
+ "components": [
604
+ {
605
+ "name": "fingerprint",
606
+ "type": "bytes",
607
+ "internalType": "bytes"
608
+ },
609
+ {
610
+ "name": "createdAt",
611
+ "type": "uint64",
612
+ "internalType": "uint64"
613
+ },
614
+ {
615
+ "name": "revokedAt",
616
+ "type": "uint64",
617
+ "internalType": "uint64"
618
+ },
619
+ {
620
+ "name": "messageVersion",
621
+ "type": "uint8",
622
+ "internalType": "uint8"
623
+ },
624
+ {
625
+ "name": "keyPtr",
626
+ "type": "address",
627
+ "internalType": "address"
628
+ },
629
+ {
630
+ "name": "sigPtr",
631
+ "type": "address",
632
+ "internalType": "address"
633
+ }
634
+ ]
635
+ }
636
+ ],
637
+ "stateMutability": "view"
638
+ },
639
+ {
640
+ "type": "function",
641
+ "name": "getPayload",
642
+ "inputs": [
643
+ {
644
+ "name": "owner",
645
+ "type": "address",
646
+ "internalType": "address"
647
+ },
648
+ {
649
+ "name": "index",
650
+ "type": "uint256",
651
+ "internalType": "uint256"
652
+ }
653
+ ],
654
+ "outputs": [
655
+ {
656
+ "name": "pgpSignature",
657
+ "type": "bytes",
658
+ "internalType": "bytes"
659
+ },
660
+ {
661
+ "name": "pgpPublicKey",
662
+ "type": "bytes",
663
+ "internalType": "bytes"
664
+ }
665
+ ],
666
+ "stateMutability": "view"
667
+ },
668
+ {
669
+ "type": "function",
670
+ "name": "nonces",
671
+ "inputs": [
672
+ {
673
+ "name": "",
674
+ "type": "address",
675
+ "internalType": "address"
676
+ }
677
+ ],
678
+ "outputs": [
679
+ {
680
+ "name": "",
681
+ "type": "uint256",
682
+ "internalType": "uint256"
683
+ }
684
+ ],
685
+ "stateMutability": "view"
686
+ },
687
+ {
688
+ "type": "function",
689
+ "name": "reattest",
690
+ "inputs": [
691
+ {
692
+ "name": "revokeIndex",
693
+ "type": "uint256",
694
+ "internalType": "uint256"
695
+ },
696
+ {
697
+ "name": "fingerprint",
698
+ "type": "bytes",
699
+ "internalType": "bytes"
700
+ },
701
+ {
702
+ "name": "pgpSignature",
703
+ "type": "bytes",
704
+ "internalType": "bytes"
705
+ },
706
+ {
707
+ "name": "pgpPublicKey",
708
+ "type": "bytes",
709
+ "internalType": "bytes"
710
+ }
711
+ ],
712
+ "outputs": [
713
+ {
714
+ "name": "index",
715
+ "type": "uint256",
716
+ "internalType": "uint256"
717
+ }
718
+ ],
719
+ "stateMutability": "nonpayable"
720
+ },
721
+ {
722
+ "type": "function",
723
+ "name": "reattestFor",
724
+ "inputs": [
725
+ {
726
+ "name": "owner",
727
+ "type": "address",
728
+ "internalType": "address"
729
+ },
730
+ {
731
+ "name": "revokeIndex",
732
+ "type": "uint256",
733
+ "internalType": "uint256"
734
+ },
735
+ {
736
+ "name": "fingerprint",
737
+ "type": "bytes",
738
+ "internalType": "bytes"
739
+ },
740
+ {
741
+ "name": "pgpSignature",
742
+ "type": "bytes",
743
+ "internalType": "bytes"
744
+ },
745
+ {
746
+ "name": "pgpPublicKey",
747
+ "type": "bytes",
748
+ "internalType": "bytes"
749
+ },
750
+ {
751
+ "name": "deadline",
752
+ "type": "uint256",
753
+ "internalType": "uint256"
754
+ },
755
+ {
756
+ "name": "signature",
757
+ "type": "bytes",
758
+ "internalType": "bytes"
759
+ }
760
+ ],
761
+ "outputs": [
762
+ {
763
+ "name": "index",
764
+ "type": "uint256",
765
+ "internalType": "uint256"
766
+ }
767
+ ],
768
+ "stateMutability": "nonpayable"
769
+ },
770
+ {
771
+ "type": "function",
772
+ "name": "record",
773
+ "inputs": [
774
+ {
775
+ "name": "owner",
776
+ "type": "address",
777
+ "internalType": "address"
778
+ },
779
+ {
780
+ "name": "index",
781
+ "type": "uint256",
782
+ "internalType": "uint256"
783
+ },
784
+ {
785
+ "name": "kind",
786
+ "type": "bytes32",
787
+ "internalType": "bytes32"
788
+ }
789
+ ],
790
+ "outputs": [
791
+ {
792
+ "name": "",
793
+ "type": "bytes",
794
+ "internalType": "bytes"
795
+ }
796
+ ],
797
+ "stateMutability": "view"
798
+ },
799
+ {
800
+ "type": "function",
801
+ "name": "revoke",
802
+ "inputs": [
803
+ {
804
+ "name": "index",
805
+ "type": "uint256",
806
+ "internalType": "uint256"
807
+ }
808
+ ],
809
+ "outputs": [],
810
+ "stateMutability": "nonpayable"
811
+ },
812
+ {
813
+ "type": "function",
814
+ "name": "revokeFor",
815
+ "inputs": [
816
+ {
817
+ "name": "owner",
818
+ "type": "address",
819
+ "internalType": "address"
820
+ },
821
+ {
822
+ "name": "index",
823
+ "type": "uint256",
824
+ "internalType": "uint256"
825
+ },
826
+ {
827
+ "name": "deadline",
828
+ "type": "uint256",
829
+ "internalType": "uint256"
830
+ },
831
+ {
832
+ "name": "signature",
833
+ "type": "bytes",
834
+ "internalType": "bytes"
835
+ }
836
+ ],
837
+ "outputs": [],
838
+ "stateMutability": "nonpayable"
839
+ },
840
+ {
841
+ "type": "function",
842
+ "name": "setRecord",
843
+ "inputs": [
844
+ {
845
+ "name": "index",
846
+ "type": "uint256",
847
+ "internalType": "uint256"
848
+ },
849
+ {
850
+ "name": "kind",
851
+ "type": "bytes32",
852
+ "internalType": "bytes32"
853
+ },
854
+ {
855
+ "name": "value",
856
+ "type": "bytes",
857
+ "internalType": "bytes"
858
+ }
859
+ ],
860
+ "outputs": [],
861
+ "stateMutability": "nonpayable"
862
+ },
863
+ {
864
+ "type": "function",
865
+ "name": "setRecordFor",
866
+ "inputs": [
867
+ {
868
+ "name": "owner",
869
+ "type": "address",
870
+ "internalType": "address"
871
+ },
872
+ {
873
+ "name": "index",
874
+ "type": "uint256",
875
+ "internalType": "uint256"
876
+ },
877
+ {
878
+ "name": "kind",
879
+ "type": "bytes32",
880
+ "internalType": "bytes32"
881
+ },
882
+ {
883
+ "name": "value",
884
+ "type": "bytes",
885
+ "internalType": "bytes"
886
+ },
887
+ {
888
+ "name": "deadline",
889
+ "type": "uint256",
890
+ "internalType": "uint256"
891
+ },
892
+ {
893
+ "name": "signature",
894
+ "type": "bytes",
895
+ "internalType": "bytes"
896
+ }
897
+ ],
898
+ "outputs": [],
899
+ "stateMutability": "nonpayable"
900
+ },
901
+ {
902
+ "type": "function",
903
+ "name": "updateKey",
904
+ "inputs": [
905
+ {
906
+ "name": "index",
907
+ "type": "uint256",
908
+ "internalType": "uint256"
909
+ },
910
+ {
911
+ "name": "pgpPublicKey",
912
+ "type": "bytes",
913
+ "internalType": "bytes"
914
+ }
915
+ ],
916
+ "outputs": [],
917
+ "stateMutability": "nonpayable"
918
+ },
919
+ {
920
+ "type": "function",
921
+ "name": "updateKeyFor",
922
+ "inputs": [
923
+ {
924
+ "name": "owner",
925
+ "type": "address",
926
+ "internalType": "address"
927
+ },
928
+ {
929
+ "name": "index",
930
+ "type": "uint256",
931
+ "internalType": "uint256"
932
+ },
933
+ {
934
+ "name": "pgpPublicKey",
935
+ "type": "bytes",
936
+ "internalType": "bytes"
937
+ },
938
+ {
939
+ "name": "deadline",
940
+ "type": "uint256",
941
+ "internalType": "uint256"
942
+ },
943
+ {
944
+ "name": "signature",
945
+ "type": "bytes",
946
+ "internalType": "bytes"
947
+ }
948
+ ],
949
+ "outputs": [],
950
+ "stateMutability": "nonpayable"
951
+ },
952
+ {
953
+ "type": "event",
954
+ "name": "Attested",
955
+ "inputs": [
956
+ {
957
+ "name": "owner",
958
+ "type": "address",
959
+ "indexed": true,
960
+ "internalType": "address"
961
+ },
962
+ {
963
+ "name": "fingerprintHash",
964
+ "type": "bytes32",
965
+ "indexed": true,
966
+ "internalType": "bytes32"
967
+ },
968
+ {
969
+ "name": "index",
970
+ "type": "uint256",
971
+ "indexed": true,
972
+ "internalType": "uint256"
973
+ },
974
+ {
975
+ "name": "fingerprint",
976
+ "type": "bytes",
977
+ "indexed": false,
978
+ "internalType": "bytes"
979
+ },
980
+ {
981
+ "name": "messageVersion",
982
+ "type": "uint8",
983
+ "indexed": false,
984
+ "internalType": "uint8"
985
+ },
986
+ {
987
+ "name": "keyPtr",
988
+ "type": "address",
989
+ "indexed": false,
990
+ "internalType": "address"
991
+ },
992
+ {
993
+ "name": "sigPtr",
994
+ "type": "address",
995
+ "indexed": false,
996
+ "internalType": "address"
997
+ },
998
+ {
999
+ "name": "submitter",
1000
+ "type": "address",
1001
+ "indexed": false,
1002
+ "internalType": "address"
1003
+ }
1004
+ ],
1005
+ "anonymous": false
1006
+ },
1007
+ {
1008
+ "type": "event",
1009
+ "name": "KeyUpdated",
1010
+ "inputs": [
1011
+ {
1012
+ "name": "owner",
1013
+ "type": "address",
1014
+ "indexed": true,
1015
+ "internalType": "address"
1016
+ },
1017
+ {
1018
+ "name": "fingerprintHash",
1019
+ "type": "bytes32",
1020
+ "indexed": true,
1021
+ "internalType": "bytes32"
1022
+ },
1023
+ {
1024
+ "name": "index",
1025
+ "type": "uint256",
1026
+ "indexed": true,
1027
+ "internalType": "uint256"
1028
+ },
1029
+ {
1030
+ "name": "oldKeyPtr",
1031
+ "type": "address",
1032
+ "indexed": false,
1033
+ "internalType": "address"
1034
+ },
1035
+ {
1036
+ "name": "newKeyPtr",
1037
+ "type": "address",
1038
+ "indexed": false,
1039
+ "internalType": "address"
1040
+ },
1041
+ {
1042
+ "name": "submitter",
1043
+ "type": "address",
1044
+ "indexed": false,
1045
+ "internalType": "address"
1046
+ }
1047
+ ],
1048
+ "anonymous": false
1049
+ },
1050
+ {
1051
+ "type": "event",
1052
+ "name": "NonceUsed",
1053
+ "inputs": [
1054
+ {
1055
+ "name": "owner",
1056
+ "type": "address",
1057
+ "indexed": true,
1058
+ "internalType": "address"
1059
+ },
1060
+ {
1061
+ "name": "nonce",
1062
+ "type": "uint256",
1063
+ "indexed": false,
1064
+ "internalType": "uint256"
1065
+ }
1066
+ ],
1067
+ "anonymous": false
1068
+ },
1069
+ {
1070
+ "type": "event",
1071
+ "name": "RecordSet",
1072
+ "inputs": [
1073
+ {
1074
+ "name": "owner",
1075
+ "type": "address",
1076
+ "indexed": true,
1077
+ "internalType": "address"
1078
+ },
1079
+ {
1080
+ "name": "index",
1081
+ "type": "uint256",
1082
+ "indexed": true,
1083
+ "internalType": "uint256"
1084
+ },
1085
+ {
1086
+ "name": "kind",
1087
+ "type": "bytes32",
1088
+ "indexed": true,
1089
+ "internalType": "bytes32"
1090
+ },
1091
+ {
1092
+ "name": "submitter",
1093
+ "type": "address",
1094
+ "indexed": false,
1095
+ "internalType": "address"
1096
+ }
1097
+ ],
1098
+ "anonymous": false
1099
+ },
1100
+ {
1101
+ "type": "event",
1102
+ "name": "Revoked",
1103
+ "inputs": [
1104
+ {
1105
+ "name": "owner",
1106
+ "type": "address",
1107
+ "indexed": true,
1108
+ "internalType": "address"
1109
+ },
1110
+ {
1111
+ "name": "fingerprintHash",
1112
+ "type": "bytes32",
1113
+ "indexed": true,
1114
+ "internalType": "bytes32"
1115
+ },
1116
+ {
1117
+ "name": "index",
1118
+ "type": "uint256",
1119
+ "indexed": true,
1120
+ "internalType": "uint256"
1121
+ },
1122
+ {
1123
+ "name": "submitter",
1124
+ "type": "address",
1125
+ "indexed": false,
1126
+ "internalType": "address"
1127
+ }
1128
+ ],
1129
+ "anonymous": false
1130
+ },
1131
+ {
1132
+ "type": "error",
1133
+ "name": "AlreadyRevoked",
1134
+ "inputs": []
1135
+ },
1136
+ {
1137
+ "type": "error",
1138
+ "name": "AuthorizationExpired",
1139
+ "inputs": []
1140
+ },
1141
+ {
1142
+ "type": "error",
1143
+ "name": "DeploymentFailed",
1144
+ "inputs": []
1145
+ },
1146
+ {
1147
+ "type": "error",
1148
+ "name": "DuplicateActiveFingerprint",
1149
+ "inputs": []
1150
+ },
1151
+ {
1152
+ "type": "error",
1153
+ "name": "EmptyPublicKey",
1154
+ "inputs": []
1155
+ },
1156
+ {
1157
+ "type": "error",
1158
+ "name": "EmptySignature",
1159
+ "inputs": []
1160
+ },
1161
+ {
1162
+ "type": "error",
1163
+ "name": "IndexOutOfBounds",
1164
+ "inputs": []
1165
+ },
1166
+ {
1167
+ "type": "error",
1168
+ "name": "InvalidAuthorization",
1169
+ "inputs": []
1170
+ },
1171
+ {
1172
+ "type": "error",
1173
+ "name": "InvalidFingerprintLength",
1174
+ "inputs": []
1175
+ },
1176
+ {
1177
+ "type": "error",
1178
+ "name": "InvalidPointer",
1179
+ "inputs": []
1180
+ },
1181
+ {
1182
+ "type": "error",
1183
+ "name": "PublicKeyTooLarge",
1184
+ "inputs": []
1185
+ },
1186
+ {
1187
+ "type": "error",
1188
+ "name": "RecordTooLarge",
1189
+ "inputs": []
1190
+ },
1191
+ {
1192
+ "type": "error",
1193
+ "name": "SignatureTooLarge",
1194
+ "inputs": []
1195
+ }
1196
+ ];
1197
+
1198
+ // src/core/contract.ts
1199
+ var REGISTRY_ADDRESS = "0x9302E02e2869e129aC8516fE5eFFd51EA3082c09";
1200
+ var NETWORKS = {
1201
+ mainnet: {
1202
+ chainId: 1,
1203
+ address: REGISTRY_ADDRESS,
1204
+ deployBlock: 25962908n,
1205
+ // 2026-09-12, tx 0xda4c3a19cae4e71ffb02559a048403f664d5a7967c19d42158c39600ec63bad8
1206
+ explorerUrl: "https://etherscan.io",
1207
+ defaultRpcUrl: "https://ethereum-rpc.publicnode.com"
1208
+ },
1209
+ sepolia: {
1210
+ chainId: 11155111,
1211
+ address: REGISTRY_ADDRESS,
1212
+ deployBlock: 11683667n,
1213
+ // 2026-09-11, tx 0x3e40e8f5b9fbf82a4b8943561bcc9b964b2987de10640ac8ff3a1b4ef0725322
1214
+ explorerUrl: "https://sepolia.etherscan.io",
1215
+ defaultRpcUrl: "https://ethereum-sepolia-rpc.publicnode.com"
1216
+ },
1217
+ /** A local anvil instance (`anvil`, chain id 31337). Deploy with pgp-registry's Deploy script. */
1218
+ local: {
1219
+ chainId: 31337,
1220
+ address: REGISTRY_ADDRESS,
1221
+ deployBlock: 0n,
1222
+ explorerUrl: "",
1223
+ defaultRpcUrl: "http://127.0.0.1:8545"
1224
+ }
1225
+ };
1226
+ function isNetworkName(value) {
1227
+ return value === "mainnet" || value === "sepolia" || value === "local";
1228
+ }
1229
+ function getRegistry(network = "mainnet", addressOverride) {
1230
+ const r = NETWORKS[network];
1231
+ if (!r) throw new Error(`Unknown network: ${network}`);
1232
+ if (addressOverride && /^0x[0-9a-fA-F]{40}$/.test(addressOverride)) {
1233
+ return { ...r, address: addressOverride };
1234
+ }
1235
+ return r;
1236
+ }
1237
+
1238
+ // src/provider.tsx
5
1239
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
6
1240
 
7
1241
  // src/context.ts
8
1242
  import { createContext, useContext } from "react";
9
1243
  var defaultConfig = {
10
- baseUrl: "https://thurin.id"
1244
+ baseUrl: "https://thurin.id",
1245
+ network: "mainnet"
11
1246
  };
12
1247
  var IdentityKitContext = createContext(defaultConfig);
13
1248
  function useIdentityKitConfig() {
@@ -24,22 +1259,25 @@ var defaultQueryClient = new QueryClient({
24
1259
  }
25
1260
  }
26
1261
  });
27
- function createDefaultWagmiConfig(rpcUrl) {
28
- return createConfig({
29
- chains: [mainnet],
30
- transports: {
31
- [mainnet.id]: http(rpcUrl || "https://ethereum-rpc.publicnode.com")
32
- }
33
- });
1262
+ function chainFor(network = "mainnet") {
1263
+ if (network === "sepolia") return sepolia;
1264
+ if (network === "local") return foundry;
1265
+ return mainnet;
1266
+ }
1267
+ function createDefaultWagmiConfig(rpcUrl, network) {
1268
+ const url = rpcUrl || getRegistry(network).defaultRpcUrl;
1269
+ if (network === "sepolia") return createConfig({ chains: [sepolia], transports: { [sepolia.id]: http(url) } });
1270
+ if (network === "local") return createConfig({ chains: [foundry], transports: { [foundry.id]: http(url) } });
1271
+ return createConfig({ chains: [mainnet], transports: { [mainnet.id]: http(url) } });
34
1272
  }
35
- function WagmiDetector({ children, rpcUrl }) {
1273
+ function WagmiDetector({ children, rpcUrl, network }) {
36
1274
  let hasWagmi = false;
37
1275
  try {
38
1276
  useConfig();
39
1277
  hasWagmi = true;
40
1278
  } catch {
41
1279
  }
42
- const wagmiConfig = useMemo(() => createDefaultWagmiConfig(rpcUrl), [rpcUrl]);
1280
+ const wagmiConfig = useMemo(() => createDefaultWagmiConfig(rpcUrl, network), [rpcUrl, network]);
43
1281
  if (hasWagmi) {
44
1282
  return /* @__PURE__ */ jsx(Fragment, { children });
45
1283
  }
@@ -49,92 +1287,83 @@ function IdentityKitProvider({
49
1287
  children,
50
1288
  rpcUrl,
51
1289
  neynarApiKey,
52
- baseUrl = "https://thurin.id"
1290
+ baseUrl = "https://thurin.id",
1291
+ network = "mainnet",
1292
+ registryAddress
53
1293
  }) {
54
1294
  const config = useMemo(
55
- () => ({ rpcUrl, neynarApiKey, baseUrl }),
56
- [rpcUrl, neynarApiKey, baseUrl]
1295
+ () => ({ rpcUrl, neynarApiKey, baseUrl, network, registryAddress }),
1296
+ [rpcUrl, neynarApiKey, baseUrl, network, registryAddress]
57
1297
  );
58
- return /* @__PURE__ */ jsx(IdentityKitContext.Provider, { value: config, children: /* @__PURE__ */ jsx(WagmiDetector, { rpcUrl, children }) });
1298
+ return /* @__PURE__ */ jsx(IdentityKitContext.Provider, { value: config, children: /* @__PURE__ */ jsx(WagmiDetector, { rpcUrl, network, children }) });
59
1299
  }
60
1300
 
61
1301
  // src/hooks/useThurinIdentity.ts
62
1302
  import { useEnsAddress, useEnsName, useEnsAvatar } from "wagmi";
63
- import { mainnet as mainnet3 } from "wagmi/chains";
64
1303
  import { normalize } from "viem/ens";
65
1304
 
66
1305
  // src/hooks/useAttestations.ts
67
1306
  import { useReadContract, useReadContracts } from "wagmi";
68
- import { mainnet as mainnet2 } from "wagmi/chains";
69
1307
  import { useQuery } from "@tanstack/react-query";
70
- import { createPublicClient, http as http2, parseAbiItem } from "viem";
1308
+ import { hexToString } from "viem";
71
1309
 
72
- // src/core/contract.ts
73
- var REGISTRY_ADDRESS = "0xf7a45BC662A78a6fb417ED5f52b3766cbf13EbBb";
74
- var CONTRACT_DEPLOY_BLOCK = 24515891n;
75
- var REGISTRY_ABI = [
76
- {
77
- name: "Attested",
78
- type: "event",
79
- inputs: [
80
- { name: "ethAddress", type: "address", indexed: true },
81
- { name: "fingerprintHash", type: "string", indexed: true },
82
- { name: "fingerprint", type: "string", indexed: false },
83
- { name: "pgpSignature", type: "string", indexed: false },
84
- { name: "pgpPublicKey", type: "string", indexed: false },
85
- { name: "index", type: "uint256", indexed: false },
86
- { name: "timestamp", type: "uint256", indexed: false }
87
- ]
88
- },
89
- {
90
- name: "attestationCount",
91
- type: "function",
92
- stateMutability: "view",
93
- inputs: [{ name: "addr", type: "address" }],
94
- outputs: [{ name: "", type: "uint256" }]
95
- },
96
- {
97
- name: "getAttestation",
98
- type: "function",
99
- stateMutability: "view",
100
- inputs: [
101
- { name: "addr", type: "address" },
102
- { name: "index", type: "uint256" }
103
- ],
104
- outputs: [
105
- { name: "fingerprint", type: "string" },
106
- { name: "createdAt", type: "uint256" },
107
- { name: "revoked", type: "bool" }
108
- ]
109
- }
110
- ];
111
-
112
- // src/core/logs.ts
113
- var LOG_CHUNK_SIZE = 49999n;
114
- async function getLogsChunked(client, params) {
115
- const latest = await client.getBlockNumber();
116
- const fromBlock = params.fromBlock ?? CONTRACT_DEPLOY_BLOCK;
117
- const toBlock = params.toBlock === "latest" || !params.toBlock ? latest : params.toBlock;
118
- const allLogs = [];
119
- for (let start = fromBlock; start <= toBlock; start += LOG_CHUNK_SIZE) {
120
- const end = start + LOG_CHUNK_SIZE - 1n > toBlock ? toBlock : start + LOG_CHUNK_SIZE - 1n;
121
- const logs = await client.getLogs({
122
- ...params,
123
- fromBlock: start,
124
- toBlock: end
125
- });
126
- allLogs.push(...logs);
127
- }
128
- return allLogs;
1310
+ // src/core/fingerprint.ts
1311
+ import { keccak256 } from "viem";
1312
+ var FINGERPRINT_HEX = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
1313
+ function normalizeFingerprint(input) {
1314
+ const hex = input.replace(/^0x/i, "").replace(/\s+/g, "").toLowerCase();
1315
+ return FINGERPRINT_HEX.test(hex) ? hex : null;
1316
+ }
1317
+ function fingerprintToBytes(fingerprint) {
1318
+ const hex = normalizeFingerprint(fingerprint);
1319
+ if (!hex) throw new Error(`Invalid PGP fingerprint: ${fingerprint}`);
1320
+ return `0x${hex}`;
1321
+ }
1322
+ function bytesToFingerprint(bytes) {
1323
+ return bytes.replace(/^0x/i, "").toLowerCase();
1324
+ }
1325
+ function fingerprintHash(fingerprint) {
1326
+ return keccak256(fingerprintToBytes(fingerprint));
1327
+ }
1328
+ function keyIdOf(fingerprint) {
1329
+ const hex = normalizeFingerprint(fingerprint);
1330
+ if (!hex) throw new Error(`Invalid PGP fingerprint: ${fingerprint}`);
1331
+ return `0x${keyIdHex(hex)}`;
1332
+ }
1333
+ function keyIdHex(normalizedFingerprint) {
1334
+ return normalizedFingerprint.length === 64 ? normalizedFingerprint.slice(0, 16) : normalizedFingerprint.slice(-16);
1335
+ }
1336
+ function keyIdToBytes(keyId) {
1337
+ const hex = keyId.replace(/^0x/i, "").replace(/\s+/g, "").toLowerCase();
1338
+ return /^[0-9a-f]{16}$/.test(hex) ? `0x${hex}` : null;
129
1339
  }
130
1340
 
131
1341
  // src/core/pgp.ts
1342
+ function algorithmName(keyOrSubkey) {
1343
+ try {
1344
+ const info = keyOrSubkey.getAlgorithmInfo();
1345
+ const curve = (info.curve || "").toLowerCase();
1346
+ if (curve.startsWith("ed25519") || info.algorithm === "ed25519" || info.algorithm === "eddsaLegacy") return "Ed25519";
1347
+ if (curve.startsWith("curve25519") || info.algorithm === "x25519") return "Cv25519";
1348
+ if (curve.startsWith("ed448")) return "Ed448";
1349
+ if (curve.startsWith("curve448") || info.algorithm === "x448") return "X448";
1350
+ if (curve.startsWith("nistp") || curve.startsWith("p")) return `NIST P-${curve.replace(/\D/g, "")}`;
1351
+ if (curve.startsWith("secp")) return curve;
1352
+ if (curve.startsWith("brainpool")) return curve;
1353
+ if (info.algorithm.startsWith("rsa")) return info.bits ? `RSA ${info.bits}` : "RSA";
1354
+ if (info.algorithm.startsWith("dsa")) return info.bits ? `DSA ${info.bits}` : "DSA";
1355
+ if (info.algorithm.startsWith("elgamal")) return info.bits ? `ElGamal ${info.bits}` : "ElGamal";
1356
+ return info.curve || info.algorithm;
1357
+ } catch {
1358
+ return String(keyOrSubkey.keyPacket?.algorithm ?? "unknown");
1359
+ }
1360
+ }
132
1361
  async function parsePgpKey(armoredKey) {
133
1362
  try {
134
1363
  const { readKey } = await import("openpgp");
135
1364
  const key = await readKey({ armoredKey });
136
1365
  const fingerprint = key.getFingerprint().toUpperCase();
137
- const algorithm = String(key.keyPacket.algorithm);
1366
+ const algorithm = algorithmName(key);
138
1367
  const created = key.keyPacket.created?.toISOString() ?? null;
139
1368
  const expiration = await key.getExpirationTime();
140
1369
  const expires = expiration && expiration !== Infinity ? new Date(expiration).toISOString() : null;
@@ -175,7 +1404,7 @@ async function parsePgpKey(armoredKey) {
175
1404
  }
176
1405
  }
177
1406
  const subkeys = key.subkeys.map((sk) => ({
178
- algorithm: String(sk.keyPacket.algorithm),
1407
+ algorithm: algorithmName(sk),
179
1408
  created: sk.keyPacket.created?.toISOString() ?? null,
180
1409
  fingerprint: sk.getFingerprint().toUpperCase()
181
1410
  }));
@@ -212,6 +1441,39 @@ async function verifyAttestation({
212
1441
  return { verified: false, reason: "Signature verification failed" };
213
1442
  }
214
1443
  }
1444
+ var EMAIL_UID = /@/;
1445
+ async function stripEmailUserIDs(armoredKey) {
1446
+ try {
1447
+ const { readKey } = await import("openpgp");
1448
+ const key = await readKey({ armoredKey });
1449
+ const kept = [];
1450
+ const removed = [];
1451
+ const users = key.users.filter((u) => {
1452
+ const uid = u.userID?.userID;
1453
+ if (!uid) return false;
1454
+ if (EMAIL_UID.test(uid)) {
1455
+ removed.push(uid);
1456
+ return false;
1457
+ }
1458
+ kept.push(uid);
1459
+ return true;
1460
+ });
1461
+ if (users.length === 0) return null;
1462
+ key.users = users;
1463
+ return { armored: key.armor(), kept, removed };
1464
+ } catch {
1465
+ return null;
1466
+ }
1467
+ }
1468
+ async function hasEmailUserID(armoredKey) {
1469
+ try {
1470
+ const { readKey } = await import("openpgp");
1471
+ const key = await readKey({ armoredKey });
1472
+ return key.users.some((u) => EMAIL_UID.test(u.userID?.userID ?? ""));
1473
+ } catch {
1474
+ return false;
1475
+ }
1476
+ }
215
1477
  var KEYSERVER_BASE = "https://keys.openpgp.org/vks/v1";
216
1478
  async function fetchKeyByFingerprint(fingerprint) {
217
1479
  try {
@@ -235,96 +1497,72 @@ async function fetchKeyByKeyId(keyId) {
235
1497
  // src/hooks/useAttestations.ts
236
1498
  function useAttestations(address) {
237
1499
  const config = useIdentityKitConfig();
238
- const { data: count, isLoading: countLoading } = useReadContract({
239
- address: REGISTRY_ADDRESS,
1500
+ const registry = getRegistry(config.network, config.registryAddress);
1501
+ const chain = chainFor(config.network);
1502
+ const owner = address;
1503
+ const { data: rows, isLoading: rowsLoading } = useReadContract({
1504
+ address: registry.address,
240
1505
  abi: REGISTRY_ABI,
241
- functionName: "attestationCount",
242
- args: address ? [address] : void 0,
243
- chainId: mainnet2.id,
244
- query: { enabled: !!address }
1506
+ functionName: "attestationsOf",
1507
+ args: owner ? [owner] : void 0,
1508
+ chainId: chain.id,
1509
+ query: { enabled: !!owner }
245
1510
  });
246
- const attestationCount = count ? Number(count) : 0;
247
- const contracts = address ? Array.from({ length: attestationCount }, (_, i) => ({
248
- address: REGISTRY_ADDRESS,
1511
+ const count = rows?.length ?? 0;
1512
+ const contracts = owner && rows ? rows.map((_, i) => ({
1513
+ address: registry.address,
249
1514
  abi: REGISTRY_ABI,
250
- functionName: "getAttestation",
251
- args: [address, BigInt(i)],
252
- chainId: mainnet2.id
1515
+ functionName: "getPayload",
1516
+ args: [owner, BigInt(i)],
1517
+ chainId: chain.id
253
1518
  })) : [];
254
- const { data: attestations, isLoading: attestationsLoading } = useReadContracts({
1519
+ const { data: payloads, isLoading: payloadsLoading } = useReadContracts({
255
1520
  contracts,
256
1521
  query: { enabled: contracts.length > 0 }
257
1522
  });
258
- const { data: eventData } = useQuery({
259
- queryKey: ["attestation-logs", address],
260
- queryFn: async () => {
261
- if (!address) return [];
262
- const client = createPublicClient({
263
- chain: mainnet2,
264
- transport: http2(config.rpcUrl || "https://ethereum-rpc.publicnode.com")
265
- });
266
- const event = parseAbiItem(
267
- "event Attested(address indexed ethAddress, string indexed fingerprintHash, string fingerprint, string pgpSignature, string pgpPublicKey, uint256 index, uint256 timestamp)"
268
- );
269
- return getLogsChunked(client, {
270
- address: REGISTRY_ADDRESS,
271
- event,
272
- args: { ethAddress: address },
273
- fromBlock: CONTRACT_DEPLOY_BLOCK,
274
- toBlock: "latest"
275
- });
276
- },
277
- enabled: !!address && attestationCount > 0,
278
- staleTime: 3e5
279
- });
1523
+ const payloadsReady = count === 0 || payloads !== void 0 && payloads.length === count;
280
1524
  const { data: claims, isLoading: verifyLoading } = useQuery({
281
- queryKey: ["attestations", address, attestationCount, !!eventData],
1525
+ queryKey: ["attestations", config.network, registry.address, address, count, payloadsReady],
282
1526
  queryFn: async () => {
283
- if (!attestations || !address) return [];
1527
+ if (!rows || !address) return [];
284
1528
  const results = [];
285
- const logsByIndex = {};
286
- for (const l of eventData || []) logsByIndex[Number(l.args.index)] = l;
287
- for (let i = 0; i < attestations.length; i++) {
288
- const att = attestations[i];
289
- if (att.status !== "success") continue;
290
- const [fingerprint, createdAt, revoked] = att.result;
291
- const log = logsByIndex[i];
292
- const pgpSignature = log?.args?.pgpSignature ?? null;
293
- const pgpPublicKey = log?.args?.pgpPublicKey ?? null;
294
- const txHash = log?.transactionHash ?? null;
295
- let verification = null;
296
- if (pgpPublicKey && pgpSignature) {
297
- verification = await verifyAttestation({
298
- pgpPublicKey,
299
- pgpSignature,
300
- fingerprint,
301
- ethAddress: address
302
- });
1529
+ for (let i = 0; i < rows.length; i++) {
1530
+ const row = rows[i];
1531
+ const payload = payloads?.[i];
1532
+ let pgpSignature = null;
1533
+ let pgpPublicKey = null;
1534
+ if (payload && payload.status === "success") {
1535
+ const [sigHex, keyHex] = payload.result;
1536
+ pgpSignature = hexToString(sigHex);
1537
+ pgpPublicKey = hexToString(keyHex);
303
1538
  }
1539
+ const fingerprint = bytesToFingerprint(row.fingerprint);
1540
+ const verification = pgpPublicKey && pgpSignature ? await verifyAttestation({ pgpPublicKey, pgpSignature, fingerprint, ethAddress: address }) : null;
1541
+ const revokedAt = Number(row.revokedAt);
304
1542
  results.push({
305
1543
  index: i,
306
1544
  fingerprint,
307
- createdAt: Number(createdAt),
308
- revoked,
1545
+ createdAt: Number(row.createdAt),
1546
+ revoked: revokedAt !== 0,
1547
+ revokedAt: revokedAt === 0 ? null : revokedAt,
1548
+ messageVersion: Number(row.messageVersion),
309
1549
  pgpSignature,
310
1550
  pgpPublicKey,
311
- txHash,
312
1551
  verification
313
1552
  });
314
1553
  }
315
1554
  return results;
316
1555
  },
317
- enabled: !!attestations && attestations.length > 0,
1556
+ enabled: !!rows && payloadsReady,
318
1557
  staleTime: 3e5
319
1558
  });
320
- const eventLogsPending = !!address && attestationCount > 0 && eventData === void 0;
321
- const isLoading = countLoading || attestationsLoading || verifyLoading || eventLogsPending;
1559
+ const isLoading = rowsLoading || payloadsLoading || verifyLoading || !!owner && rows !== void 0 && !payloadsReady;
322
1560
  const activeClaims = (claims || []).filter((c) => !c.revoked);
323
1561
  const verifiedClaims = activeClaims.filter((c) => c.verification?.verified);
324
1562
  const currentFingerprint = verifiedClaims.length > 0 ? verifiedClaims[verifiedClaims.length - 1].fingerprint : null;
325
1563
  return {
326
1564
  claims: claims || [],
327
- totalClaims: attestationCount,
1565
+ totalClaims: count,
328
1566
  activeClaims: activeClaims.length,
329
1567
  currentFingerprint,
330
1568
  isLoading
@@ -387,6 +1625,14 @@ var PROVIDERS = [
387
1625
  pattern: /^https:\/\/gist\.github\.com\/([^/]+)\/([a-f0-9]+)$/i,
388
1626
  parse: (m) => ({ user: m[1], gistId: m[2] })
389
1627
  },
1628
+ {
1629
+ // A repository's description — the form an organisation can use, since
1630
+ // gists belong to user accounts only. Same shape as the Codeberg proof.
1631
+ provider: "github",
1632
+ label: "GitHub",
1633
+ pattern: /^https:\/\/github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)$/i,
1634
+ parse: (m) => ({ user: m[1], repo: m[2] })
1635
+ },
390
1636
  {
391
1637
  provider: "dns",
392
1638
  label: "DNS",
@@ -458,6 +1704,7 @@ function containsFingerprintUrl(text, fingerprint) {
458
1704
  return text.toUpperCase().includes(fingerprint.toUpperCase());
459
1705
  }
460
1706
  async function verifyGitHub(proof, fingerprint) {
1707
+ if (proof.repo) return verifyGitHubRepo(proof, fingerprint);
461
1708
  try {
462
1709
  const resp = await fetch(`https://api.github.com/gists/${proof.gistId}`);
463
1710
  if (!resp.ok) return { verified: false, reason: `GitHub API returned ${resp.status}` };
@@ -475,6 +1722,24 @@ async function verifyGitHub(proof, fingerprint) {
475
1722
  return { verified: false, reason: `GitHub fetch failed: ${err.message}` };
476
1723
  }
477
1724
  }
1725
+ async function verifyGitHubRepo(proof, fingerprint) {
1726
+ try {
1727
+ const resp = await fetch(
1728
+ `https://api.github.com/repos/${encodeURIComponent(proof.user)}/${encodeURIComponent(proof.repo)}`
1729
+ );
1730
+ if (!resp.ok) return { verified: false, reason: `GitHub API returned ${resp.status}` };
1731
+ const data = await resp.json();
1732
+ if (data.owner?.login?.toLowerCase() !== proof.user.toLowerCase()) {
1733
+ return { verified: false, reason: "Repository owner does not match claimed account" };
1734
+ }
1735
+ if (data.description && containsFingerprint(data.description, fingerprint)) {
1736
+ return { verified: true };
1737
+ }
1738
+ return { verified: false, reason: "Fingerprint token not found in repository description" };
1739
+ } catch (err) {
1740
+ return { verified: false, reason: `GitHub fetch failed: ${err.message}` };
1741
+ }
1742
+ }
478
1743
  async function verifyDNS(proof, fingerprint) {
479
1744
  try {
480
1745
  const resp = await fetch(
@@ -559,7 +1824,7 @@ async function verifyMastodon(proof, fingerprint) {
559
1824
  );
560
1825
  if (!resp.ok) return { verified: false, reason: `Mastodon API returned ${resp.status}` };
561
1826
  const data = await resp.json();
562
- const keyId = fingerprint.slice(-16);
1827
+ const keyId = keyIdHex(fingerprint.replace(/^0x/i, "").replace(/\s+/g, "").toLowerCase());
563
1828
  for (const field of data.fields || []) {
564
1829
  const text = field.value.replace(/<[^>]*>/g, "");
565
1830
  if (containsFingerprintUrl(text, fingerprint) || containsFingerprintUrl(text, keyId)) {
@@ -591,14 +1856,14 @@ async function verifyProof(proof, fingerprint, neynarApiKey) {
591
1856
  }
592
1857
 
593
1858
  // src/hooks/usePGPProofs.ts
594
- function usePGPProofs(fingerprint) {
1859
+ function usePGPProofs(fingerprint, armoredKey) {
595
1860
  const config = useIdentityKitConfig();
596
1861
  const { data } = useQuery3({
597
- queryKey: ["pgp-proofs", fingerprint],
1862
+ // The key is large; key the query on its length + fingerprint, which
1863
+ // changes whenever a different attestation's key is supplied.
1864
+ queryKey: ["pgp-proofs", fingerprint, armoredKey?.length ?? 0],
598
1865
  queryFn: async () => {
599
- if (!fingerprint) return { keyInfo: null, proofs: [] };
600
- const armoredKey = await fetchKeyByFingerprint(fingerprint);
601
- if (!armoredKey) return { keyInfo: null, proofs: [] };
1866
+ if (!fingerprint || !armoredKey) return { keyInfo: null, proofs: [] };
602
1867
  const keyInfo = await parsePgpKey(armoredKey);
603
1868
  if (!keyInfo) return { keyInfo: null, proofs: [] };
604
1869
  const identified = keyInfo.notations.map((n) => identifyProof(n)).filter((p) => p !== null && p.provider !== "unknown");
@@ -627,7 +1892,7 @@ function usePGPProofs(fingerprint) {
627
1892
  }
628
1893
  return { keyInfo, proofs: [...byAccount.values()] };
629
1894
  },
630
- enabled: !!fingerprint,
1895
+ enabled: !!fingerprint && !!armoredKey,
631
1896
  staleTime: 3e5
632
1897
  });
633
1898
  return {
@@ -637,7 +1902,7 @@ function usePGPProofs(fingerprint) {
637
1902
  // resolved yet. Using react-query's own isLoading leaves a gap while the
638
1903
  // query is enabling (fingerprint just became known), during which the card
639
1904
  // would briefly paint without proof badges and then pop them in.
640
- isLoading: !!fingerprint && data === void 0
1905
+ isLoading: !!fingerprint && !!armoredKey && data === void 0
641
1906
  };
642
1907
  }
643
1908
 
@@ -653,23 +1918,24 @@ function safeNormalize(name) {
653
1918
  }
654
1919
  }
655
1920
  function useThurinIdentity(ensOrAddress) {
1921
+ const chain = chainFor(useIdentityKitConfig().network);
656
1922
  const isAddr = ensOrAddress ? isAddress(ensOrAddress) : false;
657
1923
  const ensInput = ensOrAddress && !isAddr ? safeNormalize(ensOrAddress) : void 0;
658
1924
  const { data: resolvedAddress } = useEnsAddress({
659
1925
  name: ensInput,
660
- chainId: mainnet3.id,
1926
+ chainId: chain.id,
661
1927
  query: { enabled: !!ensInput }
662
1928
  });
663
1929
  const address = isAddr ? ensOrAddress : resolvedAddress ?? null;
664
1930
  const { data: ensName } = useEnsName({
665
1931
  address,
666
- chainId: mainnet3.id,
1932
+ chainId: chain.id,
667
1933
  query: { enabled: !!address }
668
1934
  });
669
1935
  const displayName = ensInput || ensName || null;
670
1936
  const { data: ensAvatar } = useEnsAvatar({
671
1937
  name: displayName ? safeNormalize(displayName) : void 0,
672
- chainId: mainnet3.id,
1938
+ chainId: chain.id,
673
1939
  query: { enabled: !!displayName }
674
1940
  });
675
1941
  const {
@@ -679,11 +1945,14 @@ function useThurinIdentity(ensOrAddress) {
679
1945
  currentFingerprint,
680
1946
  isLoading: claimsLoading
681
1947
  } = useAttestations(address);
1948
+ const currentClaim = [...claims].reverse().find(
1949
+ (c) => !c.revoked && c.verification?.verified && c.fingerprint === currentFingerprint
1950
+ );
682
1951
  const {
683
1952
  keyInfo: pgpKeyInfo,
684
1953
  proofs,
685
1954
  isLoading: proofsLoading
686
- } = usePGPProofs(currentFingerprint);
1955
+ } = usePGPProofs(currentFingerprint, currentClaim?.pgpPublicKey ?? null);
687
1956
  const { efp, isLoading: efpLoading } = useEFPGraph(address);
688
1957
  return {
689
1958
  address,
@@ -776,20 +2045,144 @@ function ThurinCard({ ens, address, theme = "thurin" }) {
776
2045
  )
777
2046
  ] });
778
2047
  }
2048
+
2049
+ // src/core/authorization.ts
2050
+ import { hashTypedData, keccak256 as keccak2562, stringToHex } from "viem";
2051
+ var EIP712_NAME = "Thurin PGPRegistry";
2052
+ var EIP712_VERSION = "2";
2053
+ function registryDomain(chainId, verifyingContract) {
2054
+ return { name: EIP712_NAME, version: EIP712_VERSION, chainId, verifyingContract };
2055
+ }
2056
+ var AUTHORIZATION_TYPES = {
2057
+ Attest: [
2058
+ { name: "owner", type: "address" },
2059
+ { name: "fingerprint", type: "bytes" },
2060
+ { name: "pgpSignature", type: "bytes" },
2061
+ { name: "pgpPublicKey", type: "bytes" },
2062
+ { name: "nonce", type: "uint256" },
2063
+ { name: "deadline", type: "uint256" }
2064
+ ],
2065
+ Reattest: [
2066
+ { name: "owner", type: "address" },
2067
+ { name: "revokeIndex", type: "uint256" },
2068
+ { name: "fingerprint", type: "bytes" },
2069
+ { name: "pgpSignature", type: "bytes" },
2070
+ { name: "pgpPublicKey", type: "bytes" },
2071
+ { name: "nonce", type: "uint256" },
2072
+ { name: "deadline", type: "uint256" }
2073
+ ],
2074
+ UpdateKey: [
2075
+ { name: "owner", type: "address" },
2076
+ { name: "index", type: "uint256" },
2077
+ { name: "pgpPublicKey", type: "bytes" },
2078
+ { name: "nonce", type: "uint256" },
2079
+ { name: "deadline", type: "uint256" }
2080
+ ],
2081
+ Revoke: [
2082
+ { name: "owner", type: "address" },
2083
+ { name: "index", type: "uint256" },
2084
+ { name: "nonce", type: "uint256" },
2085
+ { name: "deadline", type: "uint256" }
2086
+ ],
2087
+ SetRecord: [
2088
+ { name: "owner", type: "address" },
2089
+ { name: "index", type: "uint256" },
2090
+ { name: "kind", type: "bytes32" },
2091
+ { name: "value", type: "bytes" },
2092
+ { name: "nonce", type: "uint256" },
2093
+ { name: "deadline", type: "uint256" }
2094
+ ]
2095
+ };
2096
+ function attestTypedData(chainId, registry, a) {
2097
+ return {
2098
+ domain: registryDomain(chainId, registry),
2099
+ types: { Attest: AUTHORIZATION_TYPES.Attest },
2100
+ primaryType: "Attest",
2101
+ message: {
2102
+ owner: a.owner,
2103
+ fingerprint: fingerprintToBytes(a.fingerprint),
2104
+ pgpSignature: stringToHex(a.pgpSignature),
2105
+ pgpPublicKey: stringToHex(a.pgpPublicKey),
2106
+ nonce: a.nonce,
2107
+ deadline: a.deadline
2108
+ }
2109
+ };
2110
+ }
2111
+ function reattestTypedData(chainId, registry, a) {
2112
+ const base = attestTypedData(chainId, registry, a);
2113
+ return {
2114
+ domain: base.domain,
2115
+ types: { Reattest: AUTHORIZATION_TYPES.Reattest },
2116
+ primaryType: "Reattest",
2117
+ message: { ...base.message, revokeIndex: a.revokeIndex }
2118
+ };
2119
+ }
2120
+ function updateKeyTypedData(chainId, registry, a) {
2121
+ return {
2122
+ domain: registryDomain(chainId, registry),
2123
+ types: { UpdateKey: AUTHORIZATION_TYPES.UpdateKey },
2124
+ primaryType: "UpdateKey",
2125
+ message: { owner: a.owner, index: a.index, pgpPublicKey: stringToHex(a.pgpPublicKey), nonce: a.nonce, deadline: a.deadline }
2126
+ };
2127
+ }
2128
+ function revokeTypedData(chainId, registry, a) {
2129
+ return {
2130
+ domain: registryDomain(chainId, registry),
2131
+ types: { Revoke: AUTHORIZATION_TYPES.Revoke },
2132
+ primaryType: "Revoke",
2133
+ message: { owner: a.owner, index: a.index, nonce: a.nonce, deadline: a.deadline }
2134
+ };
2135
+ }
2136
+ function setRecordTypedData(chainId, registry, a) {
2137
+ return {
2138
+ domain: registryDomain(chainId, registry),
2139
+ types: { SetRecord: AUTHORIZATION_TYPES.SetRecord },
2140
+ primaryType: "SetRecord",
2141
+ message: { owner: a.owner, index: a.index, kind: a.kind, value: a.value, nonce: a.nonce, deadline: a.deadline }
2142
+ };
2143
+ }
2144
+ function authorizationDigest(typedData) {
2145
+ return hashTypedData(typedData);
2146
+ }
2147
+ function recordKind(name) {
2148
+ return keccak2562(stringToHex(name));
2149
+ }
779
2150
  export {
780
- CONTRACT_DEPLOY_BLOCK,
2151
+ AUTHORIZATION_TYPES,
2152
+ EIP712_NAME,
2153
+ EIP712_VERSION,
781
2154
  IdentityKitProvider,
2155
+ NETWORKS,
782
2156
  REGISTRY_ABI,
783
2157
  REGISTRY_ADDRESS,
784
2158
  ThurinCard,
2159
+ attestTypedData,
2160
+ authorizationDigest,
2161
+ bytesToFingerprint,
2162
+ chainFor,
785
2163
  displayUrl,
786
2164
  fetchEFPGraph,
787
2165
  fetchKeyByFingerprint,
788
2166
  fetchKeyByKeyId,
2167
+ fingerprintHash,
2168
+ fingerprintToBytes,
2169
+ getRegistry,
2170
+ hasEmailUserID,
789
2171
  identifyProof,
2172
+ isNetworkName,
2173
+ keyIdOf,
2174
+ keyIdToBytes,
2175
+ normalizeFingerprint,
790
2176
  parsePgpKey,
791
2177
  proofHref,
792
2178
  proofSecondaryHref,
2179
+ reattestTypedData,
2180
+ recordKind,
2181
+ registryDomain,
2182
+ revokeTypedData,
2183
+ setRecordTypedData,
2184
+ stripEmailUserIDs,
2185
+ updateKeyTypedData,
793
2186
  useAttestations,
794
2187
  useEFPGraph,
795
2188
  usePGPProofs,