@show-karma/karma-gap-sdk 0.4.15 → 0.4.16

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.
Files changed (188) hide show
  1. package/.cursorrules +43 -0
  2. package/core/abi/AirdropNFT.json +1 -1
  3. package/core/abi/Allo.json +860 -860
  4. package/core/abi/AlloRegistry.json +578 -578
  5. package/core/abi/CommunityResolverABI.json +506 -506
  6. package/core/abi/Donations.json +251 -251
  7. package/core/abi/EAS.json +1 -1
  8. package/core/abi/MultiAttester.json +746 -746
  9. package/core/abi/ProjectResolver.json +574 -574
  10. package/core/abi/SchemaRegistry.json +1 -1
  11. package/core/abi/index.ts +21 -0
  12. package/core/class/AllGapSchemas.ts +21 -0
  13. package/core/class/Attestation.ts +429 -0
  14. package/core/class/Fetcher.ts +224 -0
  15. package/core/class/GAP.ts +481 -0
  16. package/core/class/GapSchema.ts +93 -0
  17. package/core/class/Gelato/{Gelato.js → Gelato.ts} +23 -0
  18. package/core/class/GrantProgramRegistry/Allo.ts +188 -0
  19. package/core/class/GrantProgramRegistry/AlloRegistry.ts +101 -0
  20. package/core/class/GraphQL/AxiosGQL.ts +29 -0
  21. package/core/class/GraphQL/EASClient.ts +34 -0
  22. package/core/class/GraphQL/GapEasClient.ts +869 -0
  23. package/core/class/Schema.ts +659 -0
  24. package/core/class/SchemaError.ts +42 -0
  25. package/core/class/contract/GapContract.ts +457 -0
  26. package/core/class/entities/Community.ts +148 -0
  27. package/core/class/entities/ContributorProfile.ts +108 -0
  28. package/core/class/entities/Grant.ts +321 -0
  29. package/core/class/entities/GrantUpdate.ts +187 -0
  30. package/core/class/entities/MemberOf.ts +52 -0
  31. package/core/class/entities/Milestone.ts +898 -0
  32. package/core/class/entities/Project.ts +672 -0
  33. package/core/class/entities/ProjectImpact.ts +170 -0
  34. package/core/class/entities/ProjectMilestone.ts +254 -0
  35. package/core/class/entities/ProjectPointer.ts +39 -0
  36. package/core/class/entities/ProjectUpdate.ts +176 -0
  37. package/core/class/entities/Track.ts +32 -0
  38. package/core/class/karma-indexer/GapIndexerClient.ts +383 -0
  39. package/core/class/karma-indexer/api/GapIndexerApi.ts +446 -0
  40. package/core/class/karma-indexer/api/types.ts +313 -0
  41. package/core/class/remote-storage/IpfsStorage.ts +76 -0
  42. package/core/class/remote-storage/RemoteStorage.ts +65 -0
  43. package/core/class/types/allo.ts +93 -0
  44. package/core/class/types/attestations.ts +223 -0
  45. package/core/consts.ts +775 -0
  46. package/core/scripts/create-grant.ts +102 -0
  47. package/core/scripts/create-program.ts +43 -0
  48. package/core/scripts/create-schemas.ts +65 -0
  49. package/core/scripts/deploy.ts +65 -0
  50. package/core/scripts/index.ts +1 -0
  51. package/core/scripts/milestone-multi-grants.ts +125 -0
  52. package/core/shared/types.ts +13 -0
  53. package/core/types.ts +224 -0
  54. package/core/utils/gelato/send-gelato-txn.ts +114 -0
  55. package/core/utils/gelato/sponsor-handler.ts +77 -0
  56. package/core/utils/gelato/watch-gelato-txn.ts +67 -0
  57. package/core/utils/get-date.ts +3 -0
  58. package/core/utils/get-ipfs-data.ts +13 -0
  59. package/core/utils/get-web3-provider.ts +18 -0
  60. package/core/utils/gql-queries.ts +133 -0
  61. package/core/utils/map-filter.ts +21 -0
  62. package/core/utils/serialize-bigint.ts +7 -0
  63. package/core/utils/to-unix.ts +18 -0
  64. package/create-community-example.ts +119 -0
  65. package/csv-upload/README.md +74 -0
  66. package/csv-upload/config.ts +41 -0
  67. package/csv-upload/example.csv +2 -0
  68. package/csv-upload/keys.example.json +8 -0
  69. package/csv-upload/scripts/run.ts +417 -0
  70. package/csv-upload/types.ts +39 -0
  71. package/docs/.gitkeep +0 -0
  72. package/docs/images/attestation-architecture.png +0 -0
  73. package/docs/images/dfd-get-projects.png +0 -0
  74. package/gap-schema.yaml +155 -0
  75. package/milestone-workflow-example.ts +353 -0
  76. package/package.json +45 -39
  77. package/readme.md +872 -0
  78. package/schemas/.gitkeep +0 -0
  79. package/schemas/GAP-schemas-1692135812877.json +33 -0
  80. package/test-file-indexer-api.ts +25 -0
  81. package/tsconfig.json +26 -0
  82. package/core/abi/index.d.ts +0 -1114
  83. package/core/abi/index.js +0 -26
  84. package/core/class/AllGapSchemas.d.ts +0 -9
  85. package/core/class/AllGapSchemas.js +0 -19
  86. package/core/class/Attestation.d.ts +0 -173
  87. package/core/class/Attestation.js +0 -333
  88. package/core/class/Fetcher.d.ts +0 -175
  89. package/core/class/Fetcher.js +0 -13
  90. package/core/class/GAP.d.ts +0 -254
  91. package/core/class/GAP.js +0 -289
  92. package/core/class/GapSchema.d.ts +0 -34
  93. package/core/class/GapSchema.js +0 -62
  94. package/core/class/GrantProgramRegistry/Allo.d.ts +0 -17
  95. package/core/class/GrantProgramRegistry/Allo.js +0 -137
  96. package/core/class/GrantProgramRegistry/AlloRegistry.d.ts +0 -15
  97. package/core/class/GrantProgramRegistry/AlloRegistry.js +0 -70
  98. package/core/class/GraphQL/AxiosGQL.d.ts +0 -6
  99. package/core/class/GraphQL/AxiosGQL.js +0 -25
  100. package/core/class/GraphQL/EASClient.d.ts +0 -16
  101. package/core/class/GraphQL/EASClient.js +0 -26
  102. package/core/class/GraphQL/GapEasClient.d.ts +0 -71
  103. package/core/class/GraphQL/GapEasClient.js +0 -451
  104. package/core/class/GraphQL/index.js +0 -19
  105. package/core/class/Schema.d.ts +0 -233
  106. package/core/class/Schema.js +0 -488
  107. package/core/class/SchemaError.d.ts +0 -30
  108. package/core/class/SchemaError.js +0 -39
  109. package/core/class/contract/GapContract.d.ts +0 -102
  110. package/core/class/contract/GapContract.js +0 -285
  111. package/core/class/entities/Community.d.ts +0 -34
  112. package/core/class/entities/Community.js +0 -109
  113. package/core/class/entities/ContributorProfile.d.ts +0 -41
  114. package/core/class/entities/ContributorProfile.js +0 -69
  115. package/core/class/entities/Grant.d.ts +0 -54
  116. package/core/class/entities/Grant.js +0 -223
  117. package/core/class/entities/GrantUpdate.d.ts +0 -40
  118. package/core/class/entities/GrantUpdate.js +0 -114
  119. package/core/class/entities/MemberOf.d.ts +0 -11
  120. package/core/class/entities/MemberOf.js +0 -33
  121. package/core/class/entities/Milestone.d.ts +0 -168
  122. package/core/class/entities/Milestone.js +0 -657
  123. package/core/class/entities/Project.d.ts +0 -92
  124. package/core/class/entities/Project.js +0 -418
  125. package/core/class/entities/ProjectImpact.d.ts +0 -50
  126. package/core/class/entities/ProjectImpact.js +0 -112
  127. package/core/class/entities/ProjectMilestone.d.ts +0 -60
  128. package/core/class/entities/ProjectMilestone.js +0 -174
  129. package/core/class/entities/ProjectPointer.d.ts +0 -12
  130. package/core/class/entities/ProjectPointer.js +0 -22
  131. package/core/class/entities/ProjectUpdate.d.ts +0 -50
  132. package/core/class/entities/ProjectUpdate.js +0 -110
  133. package/core/class/entities/Track.d.ts +0 -16
  134. package/core/class/entities/Track.js +0 -21
  135. package/core/class/entities/index.js +0 -26
  136. package/core/class/index.js +0 -26
  137. package/core/class/karma-indexer/GapIndexerClient.d.ts +0 -66
  138. package/core/class/karma-indexer/GapIndexerClient.js +0 -207
  139. package/core/class/karma-indexer/api/GapIndexerApi.d.ts +0 -73
  140. package/core/class/karma-indexer/api/GapIndexerApi.js +0 -256
  141. package/core/class/karma-indexer/api/types.d.ts +0 -295
  142. package/core/class/karma-indexer/api/types.js +0 -2
  143. package/core/class/remote-storage/IpfsStorage.d.ts +0 -23
  144. package/core/class/remote-storage/IpfsStorage.js +0 -56
  145. package/core/class/remote-storage/RemoteStorage.d.ts +0 -41
  146. package/core/class/remote-storage/RemoteStorage.js +0 -38
  147. package/core/class/types/allo.d.ts +0 -78
  148. package/core/class/types/allo.js +0 -2
  149. package/core/class/types/attestations.d.ts +0 -168
  150. package/core/class/types/attestations.js +0 -66
  151. package/core/consts.d.ts +0 -48
  152. package/core/consts.js +0 -641
  153. package/core/index.js +0 -24
  154. package/core/shared/types.d.ts +0 -6
  155. package/core/shared/types.js +0 -2
  156. package/core/types.d.ts +0 -131
  157. package/core/types.js +0 -13
  158. package/core/utils/gelato/index.js +0 -19
  159. package/core/utils/gelato/send-gelato-txn.d.ts +0 -55
  160. package/core/utils/gelato/send-gelato-txn.js +0 -100
  161. package/core/utils/gelato/sponsor-handler.d.ts +0 -9
  162. package/core/utils/gelato/sponsor-handler.js +0 -60
  163. package/core/utils/gelato/watch-gelato-txn.d.ts +0 -7
  164. package/core/utils/gelato/watch-gelato-txn.js +0 -63
  165. package/core/utils/get-date.d.ts +0 -1
  166. package/core/utils/get-date.js +0 -7
  167. package/core/utils/get-ipfs-data.d.ts +0 -1
  168. package/core/utils/get-ipfs-data.js +0 -20
  169. package/core/utils/get-web3-provider.d.ts +0 -2
  170. package/core/utils/get-web3-provider.js +0 -18
  171. package/core/utils/gql-queries.d.ts +0 -12
  172. package/core/utils/gql-queries.js +0 -90
  173. package/core/utils/index.js +0 -23
  174. package/core/utils/map-filter.d.ts +0 -8
  175. package/core/utils/map-filter.js +0 -20
  176. package/core/utils/serialize-bigint.d.ts +0 -1
  177. package/core/utils/serialize-bigint.js +0 -8
  178. package/core/utils/to-unix.d.ts +0 -1
  179. package/core/utils/to-unix.js +0 -25
  180. package/index.js +0 -17
  181. /package/core/class/GraphQL/{index.d.ts → index.ts} +0 -0
  182. /package/core/class/entities/{index.d.ts → index.ts} +0 -0
  183. /package/core/class/{index.d.ts → index.ts} +0 -0
  184. /package/core/{index.d.ts → index.ts} +0 -0
  185. /package/core/utils/gelato/{index.d.ts → index.ts} +0 -0
  186. /package/core/utils/{index.d.ts → index.ts} +0 -0
  187. /package/{core/class/Gelato/Gelato.d.ts → csv-upload/.gitkeep} +0 -0
  188. /package/{index.d.ts → index.ts} +0 -0
@@ -0,0 +1,457 @@
1
+ import {
2
+ MultiRevocationRequest,
3
+ getUIDsFromAttestReceipt,
4
+ } from "@ethereum-attestation-service/eas-sdk";
5
+ import {
6
+ CallbackStatus,
7
+ Hex,
8
+ RawAttestationPayload,
9
+ RawMultiAttestPayload,
10
+ SignerOrProvider,
11
+ } from "core/types";
12
+ import { Transaction } from "ethers";
13
+ import { Gelato, sendGelatoTxn } from "../../utils/gelato/send-gelato-txn";
14
+ import { serializeWithBigint } from "../../utils/serialize-bigint";
15
+ import { GAP } from "../GAP";
16
+ import { AttestationWithTx } from "../types/attestations";
17
+
18
+ type TSignature = {
19
+ r: string;
20
+ s: string;
21
+ v: string;
22
+ nonce: number;
23
+ chainId: bigint;
24
+ };
25
+
26
+ const AttestationDataTypes = {
27
+ Attest: [
28
+ { name: "payloadHash", type: "string" },
29
+ { name: "nonce", type: "uint256" },
30
+ { name: "expiry", type: "uint256" },
31
+ ],
32
+ };
33
+
34
+ export class GapContract {
35
+ static nonces: { [key: string]: number } = {};
36
+ /**
37
+ * Signs a message for the delegated attestation.
38
+ * @param signer
39
+ * @param payload
40
+ * @returns r,s,v signature
41
+ */
42
+ private static async signAttestation(
43
+ signer: SignerOrProvider,
44
+ payload: string,
45
+ expiry: bigint
46
+ ): Promise<TSignature> {
47
+ let { nonce } = await this.getNonce(signer);
48
+ const { chainId } = await signer.provider.getNetwork();
49
+
50
+ const domain = {
51
+ chainId,
52
+ name: "gap-attestation",
53
+ version: "1",
54
+ verifyingContract: (await GAP.getMulticall(signer)).address,
55
+ };
56
+
57
+ const data = { payloadHash: payload, nonce, expiry };
58
+
59
+ console.log({ domain, AttestationDataTypes, data });
60
+
61
+ const signature = await (signer as any)._signTypedData(
62
+ domain,
63
+ AttestationDataTypes,
64
+ data
65
+ );
66
+
67
+ const { r, s, v } = this.getRSV(signature);
68
+ return { r, s, v, nonce, chainId };
69
+ }
70
+
71
+ /**
72
+ * Returns the r, s, v values of a signature
73
+ * @param signature
74
+ * @returns
75
+ */
76
+ private static getRSV(signature: string) {
77
+ const r = signature.slice(0, 66);
78
+ const s = `0x${signature.slice(66, 130)}`;
79
+ const v = `0x${signature.slice(130, 132)}`;
80
+ return { r, s, v };
81
+ }
82
+
83
+ public static async getSignerAddress(signer: SignerOrProvider) {
84
+ const address =
85
+ signer.address || signer._address || (await signer.getAddress());
86
+ if (!address)
87
+ throw new Error(
88
+ "Signer does not provider either address or getAddress()."
89
+ );
90
+ return address;
91
+ }
92
+
93
+ /**
94
+ * Get nonce for the transaction
95
+ * @param address
96
+ * @returns
97
+ */
98
+ private static async getNonce(signer: SignerOrProvider) {
99
+ const contract = await GAP.getMulticall(signer);
100
+ const address = await this.getSignerAddress(signer);
101
+
102
+ console.log({ address });
103
+
104
+ const nonce = <bigint>await contract.nonces(address);
105
+ return {
106
+ nonce: Number(nonce),
107
+ next: Number(nonce + 1n),
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Send a single attestation
113
+ * @param signer
114
+ * @param payload
115
+ * @returns
116
+ */
117
+ static async attest(
118
+ signer: SignerOrProvider,
119
+ payload: RawAttestationPayload,
120
+ callback?: ((status: CallbackStatus) => void) & ((status: string) => void)
121
+ ): Promise<AttestationWithTx> {
122
+ const contract = await GAP.getMulticall(signer);
123
+
124
+ if (GAP.gelatoOpts?.useGasless) {
125
+ return this.attestBySig(signer, payload);
126
+ }
127
+ callback?.("preparing");
128
+ const tx = await contract
129
+ .attest({
130
+ schema: payload.schema,
131
+ data: payload.data.payload,
132
+ })
133
+ .then((res) => {
134
+ callback?.("pending");
135
+ return res;
136
+ });
137
+ const result = await tx.wait?.();
138
+ callback?.("confirmed");
139
+ const attestations = getUIDsFromAttestReceipt(result)[0];
140
+ const resultArray = [result].flat();
141
+
142
+ return {
143
+ tx: resultArray,
144
+ uids: [attestations as Hex],
145
+ };
146
+ }
147
+
148
+ static async attestBySig(
149
+ signer: SignerOrProvider,
150
+ payload: RawAttestationPayload
151
+ ) {
152
+ const contract = await GAP.getMulticall(signer);
153
+ const expiry = BigInt(Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 30);
154
+ const address = await this.getSignerAddress(signer);
155
+ const payloadHash = serializeWithBigint({
156
+ schema: payload.schema,
157
+ data: payload.data.raw,
158
+ });
159
+
160
+ const { r, s, v, nonce, chainId } = await this.signAttestation(
161
+ signer,
162
+ payloadHash,
163
+ expiry
164
+ );
165
+
166
+ const { data: populatedTxn } =
167
+ await contract.attestBySig.populateTransaction(
168
+ {
169
+ data: payload.data.payload,
170
+ schema: payload.schema,
171
+ },
172
+ payloadHash,
173
+ address,
174
+ nonce,
175
+ expiry,
176
+ v,
177
+ r,
178
+ s
179
+ );
180
+
181
+ if (!populatedTxn) throw new Error("Transaction data is empty");
182
+
183
+ let contractAddress = await contract.getAddress();
184
+
185
+ const txn = await sendGelatoTxn(
186
+ ...Gelato.buildArgs(populatedTxn, chainId, contractAddress as Hex)
187
+ );
188
+
189
+ const attestations = await this.getTransactionLogs(signer, txn);
190
+ return {
191
+ tx: [
192
+ {
193
+ hash: txn,
194
+ } as Transaction,
195
+ ],
196
+ uids: attestations,
197
+ };
198
+ }
199
+
200
+ /**
201
+ * Performs a referenced multi attestation.
202
+ *
203
+ * @returns an array with the attestation UIDs.
204
+ */
205
+ static async multiAttest(
206
+ signer: SignerOrProvider,
207
+ payload: RawMultiAttestPayload[],
208
+ callback?: Function
209
+ ): Promise<AttestationWithTx> {
210
+ const contract = await GAP.getMulticall(signer);
211
+
212
+ if (GAP.gelatoOpts?.useGasless) {
213
+ return this.multiAttestBySig(signer, payload);
214
+ }
215
+ if (callback) callback("preparing");
216
+
217
+ const tx = await contract.multiSequentialAttest(
218
+ payload.map((p) => p.payload)
219
+ );
220
+
221
+ if (callback) callback("pending");
222
+ const result = await tx.wait?.();
223
+ if (callback) callback("confirmed");
224
+ const attestations = getUIDsFromAttestReceipt(result);
225
+
226
+ const resultArray = [result].flat();
227
+
228
+ return {
229
+ tx: resultArray,
230
+ uids: attestations as Hex[],
231
+ };
232
+ }
233
+
234
+ /**
235
+ * Performs a referenced multi attestation.
236
+ *
237
+ * @returns an array with the attestation UIDs.
238
+ */
239
+ static async multiAttestBySig(
240
+ signer: SignerOrProvider,
241
+ payload: RawMultiAttestPayload[]
242
+ ): Promise<AttestationWithTx> {
243
+ const contract = await GAP.getMulticall(signer);
244
+ const expiry = BigInt(Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 30);
245
+ const address = await this.getSignerAddress(signer);
246
+
247
+ const payloadHash = serializeWithBigint(payload.map((p) => p.raw));
248
+
249
+ const { r, s, v, nonce, chainId } = await this.signAttestation(
250
+ signer,
251
+ payloadHash,
252
+ expiry
253
+ );
254
+
255
+ console.info({ r, s, v, nonce, chainId, payloadHash, address });
256
+
257
+ const { data: populatedTxn } =
258
+ await contract.multiSequentialAttestBySig.populateTransaction(
259
+ payload.map((p) => p.payload),
260
+ payloadHash,
261
+ address,
262
+ nonce,
263
+ expiry,
264
+ v,
265
+ r,
266
+ s
267
+ );
268
+
269
+ if (!populatedTxn) throw new Error("Transaction data is empty");
270
+
271
+ let contractAddress = await contract.getAddress();
272
+
273
+ const txn = await sendGelatoTxn(
274
+ ...Gelato.buildArgs(populatedTxn, chainId, contractAddress as Hex)
275
+ );
276
+
277
+ const attestations = await this.getTransactionLogs(signer, txn);
278
+ return {
279
+ tx: [
280
+ {
281
+ hash: txn,
282
+ } as Transaction,
283
+ ],
284
+ uids: attestations as Hex[],
285
+ };
286
+ }
287
+
288
+ static async multiRevoke(
289
+ signer: SignerOrProvider,
290
+ payload: MultiRevocationRequest[]
291
+ ): Promise<AttestationWithTx> {
292
+ const contract = await GAP.getMulticall(signer);
293
+
294
+ if (GAP.gelatoOpts?.useGasless) {
295
+ return this.multiRevokeBySig(signer, payload);
296
+ }
297
+
298
+ const tx = await contract.multiRevoke(payload);
299
+
300
+ return {
301
+ tx: [tx],
302
+ uids: [],
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Performs a referenced multi attestation.
308
+ *
309
+ * @returns an array with the attestation UIDs.
310
+ */
311
+ static async multiRevokeBySig(
312
+ signer: SignerOrProvider,
313
+ payload: MultiRevocationRequest[]
314
+ ): Promise<AttestationWithTx> {
315
+ const contract = await GAP.getMulticall(signer);
316
+ const expiry = BigInt(Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 30);
317
+ const address = await this.getSignerAddress(signer);
318
+
319
+ const payloadHash = serializeWithBigint(payload);
320
+
321
+ const { r, s, v, nonce, chainId } = await this.signAttestation(
322
+ signer,
323
+ payloadHash,
324
+ expiry
325
+ );
326
+
327
+ console.info({ r, s, v, nonce, chainId, payloadHash, address });
328
+
329
+ const { data: populatedTxn } =
330
+ await contract.multiRevokeBySig.populateTransaction(
331
+ payload,
332
+ payloadHash,
333
+ address,
334
+ nonce,
335
+ expiry,
336
+ v,
337
+ r,
338
+ s
339
+ );
340
+
341
+ if (!populatedTxn) throw new Error("Transaction data is empty");
342
+
343
+ let contractAddress = await contract.getAddress();
344
+
345
+ const txn = await sendGelatoTxn(
346
+ ...Gelato.buildArgs(populatedTxn, chainId, contractAddress as Hex)
347
+ );
348
+
349
+ return {
350
+ tx: [{ hash: txn } as Transaction],
351
+ uids: [],
352
+ };
353
+ }
354
+
355
+ /**
356
+ * Transfer the ownership of an attestation
357
+ * @param signer
358
+ * @param projectUID
359
+ * @param newOwner
360
+ * @returns
361
+ */
362
+ static async transferProjectOwnership(
363
+ signer: SignerOrProvider,
364
+ projectUID: Hex,
365
+ newOwner: Hex
366
+ ) {
367
+ const contract = await GAP.getProjectResolver(signer);
368
+ const tx = await contract.transferProjectOwnership(projectUID, newOwner);
369
+ return tx.wait?.();
370
+ }
371
+
372
+ /**
373
+ * Check if the signer is the owner of the project
374
+ * @param signer
375
+ * @param projectUID
376
+ * @param projectChainId
377
+ * @param publicAddress
378
+ * @returns
379
+ */
380
+ static async isProjectOwner(
381
+ signer: SignerOrProvider,
382
+ projectUID: Hex,
383
+ projectChainId: number,
384
+ publicAddress?: string
385
+ ): Promise<boolean> {
386
+ const contract = await GAP.getProjectResolver(signer, projectChainId);
387
+ const address = publicAddress || (await this.getSignerAddress(signer));
388
+ const isOwner = await contract.isOwner(projectUID, address);
389
+ return isOwner;
390
+ }
391
+
392
+ /**
393
+ * Check if the signer is admin of the project
394
+ * @param signer
395
+ * @param projectUID
396
+ * @param projectChainId
397
+ * @param publicAddress
398
+ * @returns
399
+ */
400
+ static async isProjectAdmin(
401
+ signer: SignerOrProvider,
402
+ projectUID: Hex,
403
+ projectChainId: number,
404
+ publicAddress?: string
405
+ ): Promise<boolean> {
406
+ const contract = await GAP.getProjectResolver(signer, projectChainId);
407
+ const address = publicAddress || (await this.getSignerAddress(signer));
408
+ const isAdmin = await contract.isAdmin(projectUID, address);
409
+ return isAdmin;
410
+ }
411
+
412
+ private static async getTransactionLogs(
413
+ signer: SignerOrProvider,
414
+ txnHash: string
415
+ ) {
416
+ const txn = await signer.provider.getTransactionReceipt(txnHash);
417
+ if (!txn || !txn.logs.length) throw new Error("Transaction not found");
418
+
419
+ // Returns the txn logs with the attestation results. Tha last two logs are the
420
+ // the ones from the GelatoRelay contract.
421
+ return getUIDsFromAttestReceipt(txn) as Hex[];
422
+ }
423
+
424
+ /**
425
+ * Add Project Admin
426
+ * @param signer
427
+ * @param projectUID
428
+ * @param newAdmin
429
+ * @returns
430
+ */
431
+ static async addProjectAdmin(
432
+ signer: SignerOrProvider,
433
+ projectUID: Hex,
434
+ newAdmin: Hex
435
+ ) {
436
+ const contract = await GAP.getProjectResolver(signer);
437
+ const tx = await contract.addAdmin(projectUID, newAdmin);
438
+ return tx.wait?.();
439
+ }
440
+
441
+ /**
442
+ * RemoveProject Admin
443
+ * @param signer
444
+ * @param projectUID
445
+ * @param newAdmin
446
+ * @returns
447
+ */
448
+ static async removeProjectAdmin(
449
+ signer: SignerOrProvider,
450
+ projectUID: Hex,
451
+ oldAdmin: Hex
452
+ ) {
453
+ const contract = await GAP.getProjectResolver(signer);
454
+ const tx = await contract.removeAdmin(projectUID, oldAdmin);
455
+ return tx.wait?.();
456
+ }
457
+ }
@@ -0,0 +1,148 @@
1
+ import { Attestation } from "../Attestation";
2
+ import {
3
+ AttestationWithTx,
4
+ CommunityDetails,
5
+ Grantee,
6
+ ICommunityDetails,
7
+ } from "../types/attestations";
8
+ import { nullRef } from "../../consts";
9
+ import { AttestationError } from "../SchemaError";
10
+ import { GapSchema } from "../GapSchema";
11
+ import { Project } from "./Project";
12
+ import {
13
+ Hex,
14
+ IAttestation,
15
+ MultiAttestPayload,
16
+ SignerOrProvider,
17
+ TNetwork,
18
+ } from "core/types";
19
+ import { GapContract } from "../contract/GapContract";
20
+ import { Grant, IGrant } from "./Grant";
21
+ import { ICommunityResponse } from "../karma-indexer/api/types";
22
+
23
+ interface _Community extends Community {}
24
+ export interface ICommunity {
25
+ community: true;
26
+ }
27
+
28
+ export class Community extends Attestation<ICommunity> {
29
+ projects: Project[] = [];
30
+ grants: Grant[] = [];
31
+ details?: CommunityDetails;
32
+
33
+ /**
34
+ * Creates the payload for a multi-attestation.
35
+ *
36
+ * > if Current payload is set, it'll be used as the base payload
37
+ * and the project should refer to an index of the current payload,
38
+ * usually the community position.
39
+ *
40
+ * @param payload
41
+ * @param refIdx
42
+ */
43
+ async multiAttestPayload() {
44
+ const payload: MultiAttestPayload = [[this, await this.payloadFor(0)]];
45
+
46
+ if (this.details) {
47
+ payload.push([this.details, await this.details.payloadFor(0)]);
48
+ }
49
+
50
+ if (this.projects?.length) {
51
+ await Promise.all(
52
+ this.projects.map(async (p) =>
53
+ payload.push(...(await p.multiAttestPayload(payload, 0)))
54
+ )
55
+ );
56
+ }
57
+
58
+ return payload;
59
+ }
60
+
61
+ /**
62
+ * Attest a community with its details.
63
+ *
64
+ * If the community exists, it will not be revoked but its details will be updated.
65
+ * @param signer
66
+ * @param details
67
+ */
68
+ async attest(
69
+ signer: SignerOrProvider,
70
+ details?: ICommunityDetails,
71
+ callback?: Function
72
+ ): Promise<AttestationWithTx> {
73
+ console.log("Attesting community");
74
+ try {
75
+ if (callback) callback("preparing");
76
+ const { tx: communityTx, uids: communityUID } = await this.schema.attest({
77
+ signer,
78
+ to: this.recipient,
79
+ refUID: nullRef,
80
+ data: this.data,
81
+ });
82
+ this._uid = communityTx[0].hash as Hex;
83
+
84
+ console.log(this.uid);
85
+ if (callback) callback("pending");
86
+
87
+ if (details) {
88
+ const communityDetails = new CommunityDetails({
89
+ data: details,
90
+ recipient: this.recipient,
91
+ refUID: this.uid,
92
+ schema: this.schema.gap.findSchema("CommunityDetails"),
93
+ });
94
+
95
+ const { tx: communityDetailsTx, uids: communityDetailsUID } =
96
+ await communityDetails.attest(signer);
97
+ return {
98
+ tx: [communityTx[0], communityDetailsTx[0]],
99
+ uids: [communityUID[0] as Hex, communityDetailsUID[0] as Hex],
100
+ };
101
+ }
102
+ if (callback) callback("confirmed");
103
+ return { tx: communityTx, uids: communityUID };
104
+ } catch (error) {
105
+ console.error(error);
106
+ throw new AttestationError(
107
+ "ATTEST_ERROR",
108
+ "Error during attestation.",
109
+ error
110
+ );
111
+ }
112
+ }
113
+
114
+ static from(
115
+ attestations: ICommunityResponse[],
116
+ network: TNetwork
117
+ ): Community[] {
118
+ return attestations.map((attestation) => {
119
+ const community = new Community({
120
+ ...attestation,
121
+ data: {
122
+ community: true,
123
+ },
124
+ schema: GapSchema.find("Community", network),
125
+ chainID: attestation.chainID,
126
+ });
127
+
128
+ if (attestation.details) {
129
+ const { details } = attestation;
130
+ community.details = new CommunityDetails({
131
+ ...details,
132
+ data: {
133
+ ...details.data,
134
+ },
135
+ schema: GapSchema.find("CommunityDetails", network),
136
+ chainID: attestation.chainID,
137
+ });
138
+ }
139
+
140
+ if (attestation.grants) {
141
+ const { grants } = attestation;
142
+ community.grants = Grant.from(grants, network);
143
+ }
144
+
145
+ return community;
146
+ });
147
+ }
148
+ }
@@ -0,0 +1,108 @@
1
+ import { Attestation, AttestationArgs } from "../Attestation";
2
+ import { AttestationWithTx } from "../types/attestations";
3
+ import { chainIdToNetwork, nullRef } from "../../consts";
4
+ import { AttestationError } from "../SchemaError";
5
+ import { GapSchema } from "../GapSchema";
6
+ import {
7
+ Hex,
8
+ MultiAttestPayload,
9
+ SignerOrProvider,
10
+ TNetwork,
11
+ } from "core/types";
12
+ import { AllGapSchemas } from "../AllGapSchemas";
13
+
14
+ export interface IContributorProfile {
15
+ name: string;
16
+ aboutMe?: string;
17
+ github?: string;
18
+ twitter?: string;
19
+ linkedin?: string;
20
+ farcaster?: string;
21
+ }
22
+
23
+ export class ContributorProfile
24
+ extends Attestation<IContributorProfile>
25
+ implements IContributorProfile
26
+ {
27
+ name: string;
28
+ aboutMe?: string;
29
+ github?: string;
30
+ twitter?: string;
31
+ linkedin?: string;
32
+ farcaster?: string;
33
+
34
+ constructor(data: AttestationArgs<IContributorProfile, GapSchema>) {
35
+ (data.data as any).type = "contributor-profile";
36
+ super(data);
37
+ }
38
+
39
+ /**
40
+ * Creates the payload for a multi-attestation.
41
+ *
42
+ * > if Current payload is set, it'll be used as the base payload
43
+ * and the project should refer to an index of the current payload,
44
+ * usually the community position.
45
+ *
46
+ * @param payload
47
+ * @param refIdx
48
+ */
49
+ async multiAttestPayload() {
50
+ const payload: MultiAttestPayload = [[this, await this.payloadFor(0)]];
51
+ return payload;
52
+ }
53
+
54
+ /**
55
+ * Attest a community with its details.
56
+ *
57
+ * If the community exists, it will not be revoked but its details will be updated.
58
+ * @param signer
59
+ * @param details
60
+ */
61
+ async attest(
62
+ signer: SignerOrProvider,
63
+ callback?: Function
64
+ ): Promise<AttestationWithTx> {
65
+ console.log("Attesting ContributorProfile");
66
+ try {
67
+ if (callback) callback("preparing");
68
+ const { tx: ContributorProfileTx, uids: ContributorProfileUID } =
69
+ await this.schema.attest({
70
+ signer,
71
+ to: this.recipient,
72
+ refUID: nullRef,
73
+ data: this.data,
74
+ });
75
+ this._uid = ContributorProfileUID[0] as Hex;
76
+
77
+ console.log(this.uid);
78
+ if (callback) callback("pending");
79
+
80
+ if (callback) callback("confirmed");
81
+ return { tx: ContributorProfileTx, uids: ContributorProfileUID };
82
+ } catch (error) {
83
+ console.error(error);
84
+ throw new AttestationError(
85
+ "ATTEST_ERROR",
86
+ "Error during attestation.",
87
+ error
88
+ );
89
+ }
90
+ }
91
+
92
+ static from(
93
+ attestation: ContributorProfile,
94
+ network: TNetwork
95
+ ): ContributorProfile {
96
+ return new ContributorProfile({
97
+ ...attestation,
98
+ data: {
99
+ ...attestation.data,
100
+ },
101
+ schema: new AllGapSchemas().findSchema(
102
+ "ContributorProfile",
103
+ chainIdToNetwork[attestation.chainID] as TNetwork
104
+ ),
105
+ chainID: attestation.chainID,
106
+ });
107
+ }
108
+ }