@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,41 @@
1
+ import { ChainConfig } from "./types";
2
+
3
+ export const CHAIN_IDS: ChainConfig = {
4
+ optimism: 10,
5
+ "optimism-sepolia": 11155420,
6
+ sepolia: 11155111,
7
+ arbitrum: 42161,
8
+ };
9
+
10
+ export const DEFAULT_CONFIG = {
11
+ DEFAULT_OWNER_ADDRESS: "0x23B7A53ecfd93803C63b97316D7362eae59C55B6",
12
+ DEFAULT_NETWORK: "optimism-sepolia" as const,
13
+ CSV_PROCESSING: {
14
+ DELAY_BETWEEN_ITEMS_MS: 2000,
15
+ ELLIPSIS_LIMIT: 100,
16
+ },
17
+ ENS_REGEX: /^\w+\.(eth)$/,
18
+ HEX_REGEX: /^0x[a-fA-F0-9]{64}$/,
19
+ };
20
+
21
+ export const API_ENDPOINTS = {
22
+ ATTESTATIONS: "/attestations",
23
+ PROJECTS: {
24
+ CHECK: "/projects/check",
25
+ },
26
+ GRANTS: {
27
+ EXTERNAL_ID: {
28
+ BULK_UPDATE: "/grants/external-id/bulk-update",
29
+ },
30
+ },
31
+ };
32
+
33
+ export const LINK_TYPES = {
34
+ WEBSITE: "website",
35
+ TWITTER: "twitter",
36
+ GITHUB: "github",
37
+ } as const;
38
+
39
+ export const GRANT_UPDATE_TYPES = {
40
+ GRANT_UPDATE: "grant-update",
41
+ } as const;
@@ -0,0 +1,2 @@
1
+ URL,Owner,Twitter,Github,Website,Project,"Project Description","If you've participated in past grant rounds, please share any new updates or milestones from the prior months",How do you measure the impact of your project?
2
+ https://explorer.gitcoin.co/#/round/424/0x222ea76664ed77d18d4416d2b2e77937b76f0a35/0x222ea76664ed77d18d4416d2b2e77937b76f0a35-5,ethdotlimo.eth,https://eth.limo,https://github.com/ethlimo,https://eth.limo,test-skywalker,"eth.limo is a privacy-preserving ENS gateway, enabling users to access Ethereum-native dApps and content. LIMO represents a shift in dweb adoption by providing an alternative means of accessing ENS resolvable domains.","Support for .art ENS domain resolution, maintained 100% uptime, 1w3.eth content pinning - this ensures fast and reliable access to ENS domain data, with multiple storage locations and a streamlined gateway to IPFS for improved speed and availability. We're also working on some back-end improvements.",
@@ -0,0 +1,8 @@
1
+ {
2
+ "optimism": {
3
+ "privateKey": "your_private_key_here",
4
+ "rpcURL": "your_rpc_url_here",
5
+ "ipfsKey": "your_ipfs_key_here"
6
+ },
7
+ "gapAccessToken": "your_gap_access_token_here"
8
+ }
@@ -0,0 +1,417 @@
1
+ import axios from "axios";
2
+ import { ethers, isAddress } from "ethers";
3
+ import * as csv from "fast-csv";
4
+ import * as fs from "fs";
5
+ import {
6
+ GAP,
7
+ Grant,
8
+ Hex,
9
+ MemberOf,
10
+ Project,
11
+ TNetwork,
12
+ nullRef,
13
+ } from "../../core";
14
+ import { GrantUpdate, IGrantUpdate } from "../../core/class";
15
+ import {
16
+ GrantDetails,
17
+ ProjectDetails,
18
+ } from "../../core/class/types/attestations";
19
+ import {
20
+ API_ENDPOINTS,
21
+ CHAIN_IDS,
22
+ DEFAULT_CONFIG,
23
+ GRANT_UPDATE_TYPES,
24
+ LINK_TYPES,
25
+ } from "../config";
26
+ import { Link } from "../types";
27
+
28
+ const [, , fileName, communityUID] = process.argv;
29
+
30
+ interface Keys {
31
+ privateKey: string;
32
+ rpcURL: string;
33
+ gapAPI: string;
34
+ ipfsKey: string;
35
+ }
36
+
37
+ interface Config {
38
+ [key: string]: Keys | string;
39
+ optimism: Keys;
40
+ "optimism-sepolia": Keys;
41
+ sepolia: Keys;
42
+ arbitrum: Keys;
43
+ "base-sepolia": Keys;
44
+ celo: Keys;
45
+ sei: Keys;
46
+ "sei-testnet": Keys;
47
+ lisk: Keys;
48
+ scroll: Keys;
49
+ gapAccessToken: string;
50
+ }
51
+
52
+ interface NetworkConfig {
53
+ networkName: TNetwork;
54
+ rpcURL: string;
55
+ gapAPI: string;
56
+ ipfsURL: string;
57
+ privateKey: string;
58
+ ipfsKey: string;
59
+ gapAccessToken: string;
60
+ }
61
+
62
+ function loadConfig(): NetworkConfig {
63
+ const networkName = DEFAULT_CONFIG.DEFAULT_NETWORK as TNetwork;
64
+ const { [networkName]: keys, gapAccessToken } = require(__dirname +
65
+ "/../keys.json") as Config;
66
+
67
+ return {
68
+ networkName,
69
+ rpcURL: keys.rpcURL,
70
+ gapAPI:
71
+ DEFAULT_CONFIG.DEFAULT_NETWORK === "optimism-sepolia"
72
+ ? "https://gapstagapi.karmahq.xyz"
73
+ : "https://gapapi.karmahq.xyz",
74
+ ipfsURL: `${keys.gapAPI}/ipfs`,
75
+ privateKey: keys.privateKey,
76
+ ipfsKey: keys.ipfsKey,
77
+ gapAccessToken: gapAccessToken,
78
+ };
79
+ }
80
+
81
+ const config = loadConfig();
82
+
83
+ const web3 = new ethers.JsonRpcProvider(config.rpcURL);
84
+ const wallet = new ethers.Wallet(config.privateKey, web3);
85
+
86
+ const gap = GAP.getInstance({ network: config.networkName });
87
+
88
+ interface CSV {
89
+ Project: string;
90
+ ProposalURL: string;
91
+ Owner: string;
92
+ Twitter: string;
93
+ Github: string;
94
+ Website: string;
95
+ FundingMapID: string;
96
+ GrantTitle: string;
97
+ "Project Description": string;
98
+ "Grant Update": string;
99
+ "Grant Title": string;
100
+ GrantDescription: string;
101
+ externalId: string;
102
+ Amount: string;
103
+ "Grant Link": string;
104
+ "Grant Objective": string;
105
+ "Grant Size Justification": string;
106
+ Updates: string;
107
+ Problem: string;
108
+ Solution: string;
109
+ }
110
+
111
+ const duplicatedGrants: {
112
+ project: {
113
+ uid: string;
114
+ name?: string;
115
+ };
116
+ grant: {
117
+ uid: string;
118
+ title?: string;
119
+ };
120
+ currentExtId: string;
121
+ candidateExtId: string;
122
+ }[] = [];
123
+
124
+ export function parseCsv<T>(
125
+ path: string,
126
+ parserFn?: (row: unknown) => Promise<void> | void
127
+ ): Promise<T[]> {
128
+ return new Promise((resolve, reject) => {
129
+ const res: T[] = [];
130
+ fs.createReadStream(path)
131
+ .pipe(csv.parse({ headers: true }))
132
+ .transform((row: unknown) => {
133
+ return row;
134
+ })
135
+ .on("data", (d) => res.push(parserFn ? parserFn(d) : d))
136
+ .on("error", reject)
137
+ .on("end", () => {
138
+ resolve(res);
139
+ });
140
+ });
141
+ }
142
+
143
+ const isEns = (str: string) => DEFAULT_CONFIG.ENS_REGEX.test(str);
144
+ const isHex = (str: string): str is Hex => DEFAULT_CONFIG.HEX_REGEX.test(str);
145
+
146
+ type DbAttestation = {
147
+ attester: string;
148
+ chainID: number;
149
+ createdAt: Date;
150
+ recipient: string;
151
+ revocationTime: number;
152
+ revoked: boolean;
153
+ schemaUID: string;
154
+ uid: string;
155
+ refUID: string;
156
+ data?: any;
157
+ type: string;
158
+ externalId?: string;
159
+ };
160
+
161
+ async function checkProjectExists(projectDetails: DbAttestation) {
162
+ try {
163
+ const { data } = await axios.post(
164
+ `${config.gapAPI}${API_ENDPOINTS.PROJECTS.CHECK}`,
165
+ projectDetails
166
+ );
167
+ return data;
168
+ } catch (e) {
169
+ return undefined;
170
+ }
171
+ }
172
+
173
+ async function updateExternalIds(
174
+ projectUID: string,
175
+ communityUID: string,
176
+ externalId: string
177
+ ) {
178
+ await axios.put(
179
+ `${config.gapAPI}${API_ENDPOINTS.GRANTS.EXTERNAL_ID.BULK_UPDATE}`,
180
+ {
181
+ projectUID,
182
+ communityUID,
183
+ externalId,
184
+ },
185
+ {
186
+ headers: {
187
+ "x-access-token": config.gapAccessToken,
188
+ },
189
+ }
190
+ );
191
+ }
192
+
193
+ async function validateInputs() {
194
+ if (!fileName || !fileName.endsWith(".csv")) {
195
+ throw new Error("Please provide a valid csv file name");
196
+ }
197
+
198
+ if (!communityUID || !isHex(communityUID)) {
199
+ throw new Error("Please provide a valid community UID");
200
+ }
201
+
202
+ if (!fs.existsSync(__dirname + `/../${fileName}`)) {
203
+ throw new Error(`File ${fileName} does not exist`);
204
+ }
205
+ }
206
+
207
+ async function bootstrap() {
208
+ try {
209
+ await validateInputs();
210
+
211
+ let missedGrants: string[] = [];
212
+ let uids: Hex[] = [];
213
+
214
+ const file = __dirname + `/../${fileName}`;
215
+ const data = await parseCsv<CSV>(file);
216
+ const filtered = data.filter((d) => isAddress(d.Owner) || isEns(d.Owner));
217
+
218
+ let count = 0;
219
+
220
+ for (const item of data) {
221
+ try {
222
+ console.log(`${count} - ${item.Project.trim()}`);
223
+ count += 1;
224
+ await new Promise((f) =>
225
+ setTimeout(f, DEFAULT_CONFIG.CSV_PROCESSING.DELAY_BETWEEN_ITEMS_MS)
226
+ );
227
+
228
+ let address =
229
+ item?.Owner?.trim() || DEFAULT_CONFIG.DEFAULT_OWNER_ADDRESS;
230
+
231
+ const slug = await gap.generateSlug(item.Project.trim());
232
+ const project = new Project({
233
+ data: { project: true },
234
+ recipient: address as Hex,
235
+ schema: gap.findSchema("Project"),
236
+ uid: nullRef,
237
+ });
238
+
239
+ const links: Link[] = [
240
+ {
241
+ type: LINK_TYPES.WEBSITE,
242
+ url: item.Website,
243
+ },
244
+ {
245
+ type: LINK_TYPES.TWITTER,
246
+ url: item.Twitter,
247
+ },
248
+ {
249
+ type: LINK_TYPES.GITHUB,
250
+ url: item.Github,
251
+ },
252
+ ];
253
+
254
+ project.details = new ProjectDetails({
255
+ data: {
256
+ description: item["Project Description"],
257
+ imageURL: "",
258
+ title: item.Project.trim(),
259
+ links,
260
+ slug,
261
+ problem: item.Problem,
262
+ solution: item.Solution,
263
+ },
264
+ refUID: project.uid,
265
+ recipient: project.recipient,
266
+ schema: gap.findSchema("ProjectDetails"),
267
+ uid: nullRef,
268
+ });
269
+
270
+ const member = new MemberOf({
271
+ data: { memberOf: true },
272
+ recipient: project.recipient,
273
+ schema: gap.findSchema("MemberOf"),
274
+ refUID: project.uid,
275
+ uid: nullRef,
276
+ });
277
+
278
+ project.members.push(member);
279
+
280
+ const grant = new Grant({
281
+ data: { communityUID: communityUID as Hex },
282
+ recipient: project.recipient,
283
+ schema: gap.findSchema("Grant"),
284
+ });
285
+
286
+ grant.details = new GrantDetails({
287
+ data: {
288
+ proposalURL: item.ProposalURL,
289
+ title: item.GrantTitle,
290
+ description: item.GrantDescription,
291
+ ...(item.Amount && { amount: item.Amount }),
292
+ payoutAddress: project.recipient,
293
+ programId: item.FundingMapID,
294
+ },
295
+ recipient: project.recipient,
296
+ schema: gap.findSchema("GrantDetails"),
297
+ });
298
+
299
+ grant.updates.push(
300
+ new GrantUpdate({
301
+ data: {
302
+ text: "Updates can be found here: " + item.ProposalURL,
303
+ type: GRANT_UPDATE_TYPES.GRANT_UPDATE,
304
+ title: "",
305
+ } as IGrantUpdate,
306
+ recipient: project.recipient,
307
+ schema: gap.findSchema("GrantDetails"),
308
+ })
309
+ );
310
+
311
+ project.grants.push(grant);
312
+
313
+ const defaultValues = {
314
+ recipient: project.recipient,
315
+ attester: project.recipient,
316
+ chainID: CHAIN_IDS[config.networkName],
317
+ createdAt: new Date(),
318
+ revocationTime: 0,
319
+ revoked: false,
320
+ };
321
+
322
+ const projectDetails: DbAttestation = {
323
+ data: {
324
+ description: item["Project Description"],
325
+ imageURL: "",
326
+ title: item.Project.trim(),
327
+ slug: slug,
328
+ },
329
+ type: "ProjectDetails",
330
+ refUID: project.uid,
331
+ schemaUID: gap.findSchema("ProjectDetails").uid,
332
+ uid: nullRef,
333
+ ...defaultValues,
334
+ };
335
+
336
+ // avoid duplicate projects
337
+ const hasProject = await checkProjectExists(projectDetails);
338
+
339
+ if (hasProject) {
340
+ const concurrentGrant = hasProject.grants.find(
341
+ (g) => g.details?.data?.title === item.GrantTitle
342
+ );
343
+
344
+ if (!concurrentGrant) {
345
+ console.log(`Didn't find grant for project ${item.Project}`);
346
+ Object.assign(grant, { refUID: hasProject.uid });
347
+ missedGrants.push(item.Project);
348
+ await grant.attest(wallet as any, hasProject.chainID);
349
+ } else {
350
+ console.log(`Found grant for project ${item.Project}`);
351
+ }
352
+
353
+ if (
354
+ item.externalId &&
355
+ concurrentGrant &&
356
+ concurrentGrant.externalId &&
357
+ concurrentGrant.externalId !== item.externalId
358
+ ) {
359
+ duplicatedGrants.push({
360
+ project: {
361
+ uid: hasProject.uid,
362
+ name: hasProject.details?.title,
363
+ },
364
+ grant: {
365
+ uid: concurrentGrant.uid,
366
+ title: concurrentGrant.details?.title,
367
+ },
368
+ currentExtId: concurrentGrant.externalId,
369
+ candidateExtId: item.externalId,
370
+ });
371
+ } else if (item.externalId) {
372
+ await updateExternalIds(
373
+ hasProject.uid,
374
+ communityUID,
375
+ item.externalId
376
+ );
377
+ }
378
+ continue;
379
+ }
380
+
381
+ try {
382
+ console.log(project.details.data);
383
+ console.log(project.grants?.[0]?.details?.data);
384
+ await project.attest(wallet as any);
385
+ uids.push(project.uid);
386
+ } catch (e) {
387
+ console.log(`Failed to save for ${item.Project}`);
388
+ }
389
+ } catch (error) {
390
+ console.error(`Error processing project ${item.Project}:`, error);
391
+ missedGrants.push(item.Project);
392
+ continue;
393
+ }
394
+ }
395
+
396
+ console.log("Attested projects: ", uids.length);
397
+ console.log(uids);
398
+
399
+ console.log("Found concurrent grants for external ids: ");
400
+ console.log(duplicatedGrants);
401
+ const concurrentGrantFile = `${__dirname}/${Date.now()}-concurrent-grants.json`;
402
+ fs.writeFileSync(
403
+ concurrentGrantFile,
404
+ JSON.stringify(duplicatedGrants, null, 2)
405
+ );
406
+ console.log(
407
+ `\x1b[36mConcurrent grants saved to ${concurrentGrantFile}\x1b[0m`
408
+ );
409
+
410
+ console.log("Missed grants:", missedGrants);
411
+ } catch (error) {
412
+ console.error("Fatal error:", error);
413
+ process.exit(1);
414
+ }
415
+ }
416
+
417
+ bootstrap();
@@ -0,0 +1,39 @@
1
+ export interface ChainConfig {
2
+ [key: string]: number;
3
+ }
4
+
5
+ export type LinkType = "website" | "twitter" | "github";
6
+
7
+ export interface Link {
8
+ type: LinkType;
9
+ url: string;
10
+ }
11
+
12
+ export interface Tag {
13
+ name: string;
14
+ }
15
+
16
+ export interface ProjectData {
17
+ description: string;
18
+ imageURL: string;
19
+ title: string;
20
+ links: Link[];
21
+ tags?: Tag[];
22
+ slug?: string;
23
+ }
24
+
25
+ export interface GrantData {
26
+ proposalURL: string;
27
+ title: string;
28
+ description: string;
29
+ amount: string;
30
+ payoutAddress: string;
31
+ cycle?: string;
32
+ season?: string;
33
+ }
34
+
35
+ export interface GrantUpdateData {
36
+ text: string;
37
+ type: string;
38
+ title: string;
39
+ }
package/docs/.gitkeep ADDED
File without changes
Binary file
@@ -0,0 +1,155 @@
1
+ DatabaseEntities:
2
+ attestation: _id, uid, schemaUID, refUID, attester, recipient, revoked, revocationTime, createdAt, updatedAt, chainID, type, data, external, txid
3
+ category: _id, name, communityId, createdAt, updatedAt
4
+ project_category: _id, category, attestationId, createdAt, updatedAt
5
+ project_contact: _id, attestationId, name, email, telegram, createdAt, updatedAt
6
+ project_subscription: _id, name, email, subscriptionUids, createdAt, updatedAt
7
+ program_registry: _id, programId, profileId, chainID, name, isValid, createdAtBlock, createdByAddress, metadata, updatedAtBlock, projectNumber, projectType, registryAddress, anchorAddress, txHash, createdAt, updatedAt, approvedAt
8
+ embeddings: _id, entityId, entityType, embeddings, createdAt, updatedAt
9
+ offchain_program_registry: _id, profileID, name, chainID, metadata, isValid, createdAt, updatedAt
10
+ bulk_project_subscription: _id, email, publicAddress, createdAt, updatedAt
11
+ project_request_intro: _id, projectUID, chainID, email, telegram, message, status, createdAt, updatedAt
12
+ external_impact: _id, data, isOnchain, createdAt, updatedAt
13
+ milestone_evaluations: _id, projectUID, grantUID, chainID, milestoneUID, description, completionText, rating, reasoning, model, createdAt, updatedAt
14
+ project_member_invite_link: _id, attestationId, hash, revoked, createdAt, updatedAt
15
+ impact_indicators: _id, name, description, unitOfMeasure, communityUID, chainID, createdAt, updatedAt
16
+ impact_segments: _id, name, description, type, categoryId, createdAt, updatedAt, impact_indicators
17
+ impact_indicator_datapoints: _id, value, startDate, endDate, proof, projectUID, chainID, impactIndicatorId, createdAt, updatedAt
18
+
19
+ # This is how GAP stores its entities
20
+ Community:
21
+ type: attestation[]
22
+ reference: type("Community")
23
+ description: Used as the main entity for communities
24
+ relationships:
25
+ Details:
26
+ type: attestation
27
+ reference: refUID(Community.uid), type("CommunityDetails")
28
+ description: Details about the Community - always use the latest CommunityDetails by createdAt
29
+
30
+ Grant:
31
+ type: attestation
32
+ reference: refUID(Project.uid) data.communityUID(Community.uid), type("Grant")
33
+ description: Grants within a community recieved by a project
34
+ extras: external.gitcoin => contains gitcoin projectIds for the project, external.octant => contains octant projectIds for the project
35
+ relationships:
36
+ Details:
37
+ type: attestation
38
+ reference: refUID(Grant.uid), type("GrantDetails")
39
+ description: Details about the Grant - always use the latest GrantDetails by createdAt
40
+
41
+ Project:
42
+ type: attestation[]
43
+ reference: refUID(Project.uid), uid(Grant.uid), type("Project")
44
+ description: Used as the main entity for the projects
45
+ extras: external.oso[] => contains OSO(Open Source Obeservatory) slugs for the project, external.contractAddresses[] = ["0x123", "0x456"], contract addresses of the project
46
+ relationships:
47
+ Details:
48
+ type: attestation
49
+ reference: refUID(Project.uid), type("ProjectDetails")
50
+ description: Details about the Project - always use the latest ProjectDetails by createdAt
51
+
52
+ ProjectPointer:
53
+ type: attestation[]
54
+ reference: refUID(ProjectB.uid), type("ProjectPointer"), data.ogProjectUID(ProjectA.uid)
55
+ description: Pointer to the original project - used for merging projects
56
+
57
+ ProjectImpact:
58
+ type: attestation[]
59
+ reference: refUID(Project.uid), type("ProjectImpact")
60
+ description: Impacts of the project
61
+ relationship:
62
+ ProjectImpactVerified:
63
+ type: attestation[]
64
+ reference: refUID(ProjectImpact.uid), type("ProjectImpactVerified")
65
+ description: Used to show the show verifications of the Project Impact
66
+
67
+ ProjectMilestone:
68
+ type: attestation[]
69
+ reference: refUID(Project.uid), type("ProjectMilestone")
70
+ description: Milestones of the project
71
+ relationships:
72
+ ProjectMilestoneCompleted:
73
+ type: attestation[]
74
+ reference: refUID(ProjectMilestone.uid), type("ProjectMilestoneCompleted")
75
+ description: Entity to track if a milestone is completed
76
+
77
+ ProjectEndorsement:
78
+ type: attestation[]
79
+ reference: refUID(Project.uid), type("ProjectEndorsement")
80
+ description: Endorsements of the project
81
+
82
+ ProjectUpdate:
83
+ type: attestation[]
84
+ reference: refUID(Project.uid), type("ProjectUpdate")
85
+ description: Updates of the project
86
+
87
+ MemberOf:
88
+ type: attestation[]
89
+ reference: refUID(Project.uid), type("MemberOf")
90
+ description: Members of the project are represented in recipient(0x{string})
91
+
92
+ ProjectCategory:
93
+ type: project_category[]
94
+ references: attestationId(Project._id), categoryId(Category._id)
95
+ description: Mapping of categories to projects
96
+
97
+ GrantUpdate:
98
+ type: attestation[]
99
+ reference: refUID(Grant.uid), type("GrantUpdate")
100
+ description: Updates of a recieved Grant
101
+ relationships:
102
+ GrantUpdateStatus:
103
+ type: attestation
104
+ reference: refUID(GrantUpdate.uid), type("GrantUpdateStatus")
105
+ description: Used to describe the status of a GrantUpdate. data.type("grant-update-verified") is used to show verified
106
+
107
+ Milestone:
108
+ type: attestation[]
109
+ reference: refUID(Grant.uid), type("Milestone")
110
+ description: Milestones of a grant
111
+ relationships:
112
+ MilestoneStatus:
113
+ type: attestation
114
+ reference: refUID(Milestone.uid), type("MilestoneStatus")
115
+ description: Used to describe the status of a Milestone. data.type("verified") is used to show verified and data.type("completed") is for completed
116
+
117
+ Program:
118
+ type: program_registry
119
+ reference: data.programId(`${Program.programId}_${Program.chainID}`), type("GrantDetails")
120
+ description: Contains all the Grant programs in the funding map
121
+ relationships:
122
+ Community:
123
+ type: attestation[]
124
+ reference: metadata.communityRef[](Community.uid)
125
+ description: Communities linked to this program explicitly
126
+
127
+ ImpactIndicators:
128
+ type: impact_indicators[]
129
+ reference: communityUID(Community.uid)
130
+ description: Indicators within a Community
131
+ relationships:
132
+ ImpactIndicatorDatapoints:
133
+ type: impact_indicator_datapoints[]
134
+ reference: impactIndicatorId(ImpactIndicator._id), projectUID(Project.uid))
135
+ description: Data points stored for an Impact Indicator for a project
136
+
137
+ Category:
138
+ type: category
139
+ reference: communityId(Community._id)
140
+ description: Categories of projects in a community
141
+ relationships:
142
+ ProjectCategory:
143
+ type: project_category[]
144
+ reference: categoryId(Category._id) attestationId(Project._id)
145
+ description: Mapping of Categories to Projects
146
+
147
+ ImpactSegment:
148
+ type: impact_segments
149
+ reference: categoryId(Category._id)
150
+ description: Impact segments our output/outcome groups of indicators for a category of projects
151
+ relationships:
152
+ ImpactIndicator:
153
+ type: impact_indicators
154
+ reference: impact_indicators(impact_indicators._id)[]
155
+ description: List of impact indicators grouped under this impact segment