@show-karma/karma-gap-sdk 0.4.11 → 0.4.12

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.
@@ -0,0 +1,117 @@
1
+ [
2
+ {
3
+ "inputs": [
4
+ {
5
+ "internalType": "bytes32",
6
+ "name": "_profileId",
7
+ "type": "bytes32"
8
+ },
9
+ {
10
+ "internalType": "address",
11
+ "name": "_strategy",
12
+ "type": "address"
13
+ },
14
+ {
15
+ "internalType": "bytes",
16
+ "name": "_initStrategyData",
17
+ "type": "bytes"
18
+ },
19
+ {
20
+ "internalType": "address",
21
+ "name": "_token",
22
+ "type": "address"
23
+ },
24
+ {
25
+ "internalType": "uint256",
26
+ "name": "_amount",
27
+ "type": "uint256"
28
+ },
29
+ {
30
+ "components": [
31
+ {
32
+ "internalType": "uint256",
33
+ "name": "protocol",
34
+ "type": "uint256"
35
+ },
36
+ {
37
+ "internalType": "string",
38
+ "name": "pointer",
39
+ "type": "string"
40
+ }
41
+ ],
42
+ "internalType": "struct IAllo.Metadata",
43
+ "name": "_metadata",
44
+ "type": "tuple"
45
+ },
46
+ {
47
+ "internalType": "address[]",
48
+ "name": "_managers",
49
+ "type": "address[]"
50
+ }
51
+ ],
52
+ "name": "createPool",
53
+ "outputs": [
54
+ {
55
+ "internalType": "uint256",
56
+ "name": "poolId",
57
+ "type": "uint256"
58
+ }
59
+ ],
60
+ "stateMutability": "payable",
61
+ "type": "function"
62
+ },
63
+ {
64
+ "inputs": [
65
+ {
66
+ "internalType": "uint256",
67
+ "name": "_poolId",
68
+ "type": "uint256"
69
+ },
70
+ {
71
+ "components": [
72
+ {
73
+ "internalType": "uint256",
74
+ "name": "protocol",
75
+ "type": "uint256"
76
+ },
77
+ {
78
+ "internalType": "string",
79
+ "name": "pointer",
80
+ "type": "string"
81
+ }
82
+ ],
83
+ "internalType": "struct IAllo.Metadata",
84
+ "name": "_metadata",
85
+ "type": "tuple"
86
+ }
87
+ ],
88
+ "name": "updatePoolMetadata",
89
+ "outputs": [],
90
+ "stateMutability": "nonpayable",
91
+ "type": "function"
92
+ },
93
+ {
94
+ "inputs": [
95
+ {
96
+ "internalType": "address",
97
+ "name": "_alloAddress",
98
+ "type": "address"
99
+ }
100
+ ],
101
+ "stateMutability": "nonpayable",
102
+ "type": "constructor"
103
+ },
104
+ {
105
+ "inputs": [],
106
+ "name": "allo",
107
+ "outputs": [
108
+ {
109
+ "internalType": "contract IAllo",
110
+ "name": "",
111
+ "type": "address"
112
+ }
113
+ ],
114
+ "stateMutability": "view",
115
+ "type": "function"
116
+ }
117
+ ]
@@ -1,5 +1,5 @@
1
- import { SchemaInterface, TNetwork, TSchemaName } from '../types';
2
- import { GapSchema } from './GapSchema';
1
+ import { SchemaInterface, TNetwork, TSchemaName } from "../types";
2
+ import { GapSchema } from "./GapSchema";
3
3
  export declare class AllGapSchemas {
4
4
  allSchemas: {
5
5
  [network: string]: SchemaInterface<TSchemaName>[];
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AllGapSchemas = void 0;
4
4
  const consts_1 = require("../../core/consts");
5
- const GapSchema_1 = require("./GapSchema");
6
5
  const GAP_1 = require("./GAP");
6
+ const GapSchema_1 = require("./GapSchema");
7
7
  class AllGapSchemas {
8
8
  constructor() {
9
9
  this.allSchemas = {};
@@ -12,8 +12,8 @@ class AllGapSchemas {
12
12
  });
13
13
  }
14
14
  findSchema(name, network) {
15
- const schema = this.allSchemas[network].find(s => s.name === name);
16
- return new GapSchema_1.GapSchema(schema, new GAP_1.GAP({ network: network }), false, false);
15
+ const schema = this.allSchemas[network].find((s) => s.name === name);
16
+ return new GapSchema_1.GapSchema(schema, GAP_1.GAP.getInstance({ network }), false, false);
17
17
  }
18
18
  }
19
19
  exports.AllGapSchemas = AllGapSchemas;
@@ -1,7 +1,7 @@
1
- import { AttestArgs, Facade, SchemaInterface, TNetwork, TSchemaName, SignerOrProvider } from "../types";
2
- import { GapSchema } from "./GapSchema";
3
1
  import { ethers } from "ethers";
2
+ import { AttestArgs, Facade, SchemaInterface, SignerOrProvider, TNetwork, TSchemaName } from "../types";
4
3
  import { Fetcher } from "./Fetcher";
4
+ import { GapSchema } from "./GapSchema";
5
5
  import { RemoteStorage } from "./remote-storage/RemoteStorage";
6
6
  interface GAPArgs {
7
7
  network: TNetwork;
@@ -101,7 +101,8 @@ interface GAPArgs {
101
101
  *
102
102
  * This is the main class that is used to interact with the GAP SDK.
103
103
  *
104
- * This class can behave as a singleton or as a regular class.
104
+ * This class implements the singleton pattern to ensure only one instance exists
105
+ * throughout the application lifecycle.
105
106
  *
106
107
  * Using this class, the user will be able to:
107
108
  *
@@ -136,12 +137,16 @@ interface GAPArgs {
136
137
  *
137
138
  * const schemas = MountEntities(Networks.sepolia);
138
139
  *
139
- * const gap = new GAP({
140
+ * // Initialize the singleton instance
141
+ * const gap = GAP.getInstance({
140
142
  * network: "sepolia",
141
143
  * owner: "0xd7d1DB401EA825b0325141Cd5e6cd7C2d01825f2",
142
144
  * schemas: Object.values(schemas),
143
145
  * });
144
146
  *
147
+ * // Later in the code, get the same instance
148
+ * const sameGap = GAP.getInstance();
149
+ *
145
150
  * gap.fetcher
146
151
  * .fetchProjects()
147
152
  * .then((res) => {
@@ -152,10 +157,23 @@ interface GAPArgs {
152
157
  */
153
158
  export declare class GAP extends Facade {
154
159
  private static remoteStorage?;
160
+ private static instances;
155
161
  readonly fetch: Fetcher;
156
162
  readonly network: TNetwork;
157
163
  private _schemas;
158
164
  private static _gelatoOpts;
165
+ /**
166
+ * Get the singleton instance of GAP for a specific network.
167
+ * If no instance exists for the network, creates one with the provided args.
168
+ * @param args Optional initialization arguments
169
+ * @returns The singleton instance of GAP for the specified network
170
+ */
171
+ static getInstance(args?: GAPArgs): GAP;
172
+ /**
173
+ * Creates a new instance of GAP.
174
+ * You can either use this constructor directly or use the singleton pattern via getInstance().
175
+ * @param args Initialization arguments
176
+ */
159
177
  constructor(args: GAPArgs);
160
178
  private assertGelatoOpts;
161
179
  /**
package/core/class/GAP.js CHANGED
@@ -4,24 +4,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.GAP = void 0;
7
+ const CommunityResolverABI_json_1 = __importDefault(require("../abi/CommunityResolverABI.json"));
7
8
  const MultiAttester_json_1 = __importDefault(require("../abi/MultiAttester.json"));
8
9
  const ProjectResolver_json_1 = __importDefault(require("../abi/ProjectResolver.json"));
9
- const CommunityResolverABI_json_1 = __importDefault(require("../abi/CommunityResolverABI.json"));
10
- const types_1 = require("../types");
11
- const Schema_1 = require("./Schema");
12
- const GapSchema_1 = require("./GapSchema");
13
10
  const eas_sdk_1 = require("@ethereum-attestation-service/eas-sdk");
14
- const consts_1 = require("../consts");
15
11
  const ethers_1 = require("ethers");
16
12
  const package_json_1 = require("../../package.json");
17
- const GraphQL_1 = require("./GraphQL");
13
+ const consts_1 = require("../consts");
14
+ const types_1 = require("../types");
18
15
  const get_web3_provider_1 = require("../utils/get-web3-provider");
16
+ const GapSchema_1 = require("./GapSchema");
17
+ const GraphQL_1 = require("./GraphQL");
18
+ const Schema_1 = require("./Schema");
19
19
  /**
20
20
  * GAP SDK Facade.
21
21
  *
22
22
  * This is the main class that is used to interact with the GAP SDK.
23
23
  *
24
- * This class can behave as a singleton or as a regular class.
24
+ * This class implements the singleton pattern to ensure only one instance exists
25
+ * throughout the application lifecycle.
25
26
  *
26
27
  * Using this class, the user will be able to:
27
28
  *
@@ -56,12 +57,16 @@ const get_web3_provider_1 = require("../utils/get-web3-provider");
56
57
  *
57
58
  * const schemas = MountEntities(Networks.sepolia);
58
59
  *
59
- * const gap = new GAP({
60
+ * // Initialize the singleton instance
61
+ * const gap = GAP.getInstance({
60
62
  * network: "sepolia",
61
63
  * owner: "0xd7d1DB401EA825b0325141Cd5e6cd7C2d01825f2",
62
64
  * schemas: Object.values(schemas),
63
65
  * });
64
66
  *
67
+ * // Later in the code, get the same instance
68
+ * const sameGap = GAP.getInstance();
69
+ *
65
70
  * gap.fetcher
66
71
  * .fetchProjects()
67
72
  * .then((res) => {
@@ -71,6 +76,32 @@ const get_web3_provider_1 = require("../utils/get-web3-provider");
71
76
  * ```
72
77
  */
73
78
  class GAP extends types_1.Facade {
79
+ /**
80
+ * Get the singleton instance of GAP for a specific network.
81
+ * If no instance exists for the network, creates one with the provided args.
82
+ * @param args Optional initialization arguments
83
+ * @returns The singleton instance of GAP for the specified network
84
+ */
85
+ static getInstance(args) {
86
+ if (!args) {
87
+ throw new Error("Network must be specified when getting GAP instance");
88
+ }
89
+ const existingInstance = GAP.instances.get(args.network);
90
+ if (existingInstance) {
91
+ return existingInstance;
92
+ }
93
+ if (!args) {
94
+ throw new Error("Initialization arguments required for first instance");
95
+ }
96
+ const newInstance = new GAP(args);
97
+ GAP.instances.set(args.network, newInstance);
98
+ return newInstance;
99
+ }
100
+ /**
101
+ * Creates a new instance of GAP.
102
+ * You can either use this constructor directly or use the singleton pattern via getInstance().
103
+ * @param args Initialization arguments
104
+ */
74
105
  constructor(args) {
75
106
  super();
76
107
  /**
@@ -82,13 +113,13 @@ class GAP extends types_1.Facade {
82
113
  let slug = text
83
114
  .toLowerCase()
84
115
  // Remove emojis
85
- .replace(/([\uE000-\uF8FF]|\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDDFF])/g, '')
116
+ .replace(/([\uE000-\uF8FF]|\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDDFF])/g, "")
86
117
  // Remove basic text emoticons
87
- .replace(/[:;=][()DP]/g, '')
118
+ .replace(/[:;=][()DP]/g, "")
88
119
  .replace(/ /g, "-")
89
120
  .replace(/[^\w-]+/g, "")
90
121
  .trim()
91
- .replace(/^-+|-+$/g, ''); // Remove leading and trailing hyphens
122
+ .replace(/^-+|-+$/g, ""); // Remove leading and trailing hyphens
92
123
  const checkSlug = async (currentSlug, counter = 0) => {
93
124
  const slugToCheck = counter === 0 ? currentSlug : `${currentSlug}-${counter}`;
94
125
  const slugExists = await this.fetch.slugExists(slugToCheck);
@@ -114,6 +145,7 @@ class GAP extends types_1.Facade {
114
145
  this._schemas = schemas.map((schema) => new GapSchema_1.GapSchema(schema, this, false, args.globalSchemas ? !args.globalSchemas : false));
115
146
  Schema_1.Schema.validate(this.network);
116
147
  console.info(`Loaded GAP SDK v${package_json_1.version} for network ${this.network}`);
148
+ GAP.instances.set(this.network, this);
117
149
  }
118
150
  assertGelatoOpts(args) {
119
151
  if (args.gelatoOpts &&
@@ -253,4 +285,5 @@ class GAP extends types_1.Facade {
253
285
  }
254
286
  }
255
287
  exports.GAP = GAP;
288
+ GAP.instances = new Map();
256
289
  GAP._gelatoOpts = null;
@@ -483,4 +483,5 @@ Schema.schemas = {
483
483
  sei: [],
484
484
  "sei-testnet": [],
485
485
  "base-sepolia": [],
486
+ lisk: [],
486
487
  };
@@ -1,5 +1,5 @@
1
1
  import { Transaction } from "ethers";
2
- import { MultiAttestPayload, SignerOrProvider, TNetwork } from "../../types";
2
+ import { Hex, MultiAttestPayload, MultiRevokeArgs, SignerOrProvider, TNetwork } from "../../types";
3
3
  import { Attestation } from "../Attestation";
4
4
  import { GapSchema } from "../GapSchema";
5
5
  import { IMilestoneResponse } from "../karma-indexer/api/types";
@@ -12,6 +12,16 @@ export interface IMilestone {
12
12
  type?: string;
13
13
  priority?: number;
14
14
  }
15
+ /**
16
+ * Milestone class represents a milestone that can be attested to one or multiple grants.
17
+ *
18
+ * It provides methods to:
19
+ * - Create, complete, approve, reject, and verify milestones
20
+ * - Attest a milestone to a single grant
21
+ * - Attest a milestone to multiple grants in a single transaction
22
+ * - Complete, approve, and verify milestones across multiple grants
23
+ * - Revoke multiple milestone attestations at once
24
+ */
15
25
  export declare class Milestone extends Attestation<IMilestone> implements IMilestone {
16
26
  title: string;
17
27
  startsAt?: number;
@@ -30,6 +40,16 @@ export declare class Milestone extends Attestation<IMilestone> implements IMiles
30
40
  * @param reason
31
41
  */
32
42
  approve(signer: SignerOrProvider, data?: IMilestoneCompleted, callback?: Function): Promise<void>;
43
+ /**
44
+ * Approves this milestone across multiple grants. If the milestones are not completed,
45
+ * it will throw an error.
46
+ * @param signer - The signer to use for attestation
47
+ * @param milestoneUIDs - Array of milestone UIDs to approve
48
+ * @param data - Optional approval data
49
+ * @param callback - Optional callback function for status updates
50
+ * @returns Promise with transaction and UIDs
51
+ */
52
+ approveMultipleGrants(signer: SignerOrProvider, milestoneUIDs: Hex[], data?: IMilestoneCompleted, callback?: Function): Promise<AttestationWithTx>;
33
53
  /**
34
54
  * Revokes the approved status of the milestone. If the milestone is not approved,
35
55
  * it will throw an error.
@@ -52,6 +72,16 @@ export declare class Milestone extends Attestation<IMilestone> implements IMiles
52
72
  tx: Transaction[];
53
73
  uids: `0x${string}`[];
54
74
  }>;
75
+ /**
76
+ * Revokes multiple milestone attestations at once.
77
+ * This method can be used to revoke multiple milestone attestations in a single transaction.
78
+ *
79
+ * @param signer - The signer to use for revocation
80
+ * @param attestationsToRevoke - Array of objects containing schemaId and uid of attestations to revoke
81
+ * @param callback - Optional callback function for status updates
82
+ * @returns Promise with transaction and UIDs of revoked attestations
83
+ */
84
+ revokeMultipleAttestations(signer: SignerOrProvider, attestationsToRevoke: MultiRevokeArgs[], callback?: Function): Promise<AttestationWithTx>;
55
85
  /**
56
86
  * Marks a milestone as completed. If the milestone is already completed,
57
87
  * it will throw an error.
@@ -59,6 +89,16 @@ export declare class Milestone extends Attestation<IMilestone> implements IMiles
59
89
  * @param reason
60
90
  */
61
91
  complete(signer: SignerOrProvider, data?: IMilestoneCompleted, callback?: Function): Promise<AttestationWithTx>;
92
+ /**
93
+ * Marks a milestone as completed across multiple grants. If the milestone is already completed,
94
+ * it will throw an error.
95
+ * @param signer - The signer to use for attestation
96
+ * @param grantIndices - Array of grant indices to attest this milestone to, or array of milestone UIDs
97
+ * @param data - Optional completion data
98
+ * @param callback - Optional callback function for status updates
99
+ * @returns Promise with transaction and UIDs
100
+ */
101
+ completeForMultipleGrants(signer: SignerOrProvider, grantIndicesOrMilestoneUIDs?: number[] | Hex[], data?: IMilestoneCompleted, callback?: Function): Promise<AttestationWithTx>;
62
102
  /**
63
103
  * Revokes the completed status of the milestone. If the milestone is not completed,
64
104
  * it will throw an error.
@@ -79,6 +119,26 @@ export declare class Milestone extends Attestation<IMilestone> implements IMiles
79
119
  * @param grantIdx
80
120
  */
81
121
  multiAttestPayload(currentPayload?: MultiAttestPayload, grantIdx?: number): Promise<[Attestation<unknown, GapSchema>, import("../../types").RawMultiAttestPayload][]>;
122
+ /**
123
+ * Creates the payload for a multi-attestation across multiple grants.
124
+ *
125
+ * This method allows for the same milestone to be attested to multiple grants
126
+ * in a single transaction.
127
+ *
128
+ * @param currentPayload - Current payload to append to
129
+ * @param grantIndices - Array of grant indices to attest this milestone to
130
+ * @returns The multi-attest payload with all grant attestations
131
+ */
132
+ multiGrantAttestPayload(currentPayload?: MultiAttestPayload, grantIndices?: number[]): Promise<[Attestation<unknown, GapSchema>, import("../../types").RawMultiAttestPayload][]>;
133
+ /**
134
+ * Attests this milestone to multiple grants in a single transaction.
135
+ *
136
+ * @param signer - The signer to use for attestation
137
+ * @param grantIndices - Array of grant indices to attest this milestone to, or array of grant UIDs
138
+ * @param callback - Optional callback function for status updates
139
+ * @returns Promise with transaction and UIDs
140
+ */
141
+ attestToMultipleGrants(signer: SignerOrProvider, grantIndices?: number[] | Hex[], callback?: Function): Promise<AttestationWithTx>;
82
142
  /**
83
143
  * @inheritdoc
84
144
  */
@@ -95,4 +155,14 @@ export declare class Milestone extends Attestation<IMilestone> implements IMiles
95
155
  * @param reason
96
156
  */
97
157
  verify(signer: SignerOrProvider, data?: IMilestoneCompleted, callback?: Function): Promise<AttestationWithTx>;
158
+ /**
159
+ * Verifies this milestone across multiple grants. If the milestones are not completed,
160
+ * it will throw an error.
161
+ * @param signer - The signer to use for attestation
162
+ * @param milestoneUIDs - Array of milestone UIDs to verify
163
+ * @param data - Optional verification data
164
+ * @param callback - Optional callback function for status updates
165
+ * @returns Promise with transaction and UIDs
166
+ */
167
+ verifyMultipleGrants(signer: SignerOrProvider, milestoneUIDs: Hex[], data?: IMilestoneCompleted, callback?: Function): Promise<AttestationWithTx>;
98
168
  }
@@ -7,6 +7,16 @@ const Attestation_1 = require("../Attestation");
7
7
  const SchemaError_1 = require("../SchemaError");
8
8
  const GapContract_1 = require("../contract/GapContract");
9
9
  const attestations_1 = require("../types/attestations");
10
+ /**
11
+ * Milestone class represents a milestone that can be attested to one or multiple grants.
12
+ *
13
+ * It provides methods to:
14
+ * - Create, complete, approve, reject, and verify milestones
15
+ * - Attest a milestone to a single grant
16
+ * - Attest a milestone to multiple grants in a single transaction
17
+ * - Complete, approve, and verify milestones across multiple grants
18
+ * - Revoke multiple milestone attestations at once
19
+ */
10
20
  class Milestone extends Attestation_1.Attestation {
11
21
  constructor() {
12
22
  super(...arguments);
@@ -45,6 +55,66 @@ class Milestone extends Attestation_1.Attestation {
45
55
  recipient: this.recipient,
46
56
  });
47
57
  }
58
+ /**
59
+ * Approves this milestone across multiple grants. If the milestones are not completed,
60
+ * it will throw an error.
61
+ * @param signer - The signer to use for attestation
62
+ * @param milestoneUIDs - Array of milestone UIDs to approve
63
+ * @param data - Optional approval data
64
+ * @param callback - Optional callback function for status updates
65
+ * @returns Promise with transaction and UIDs
66
+ */
67
+ async approveMultipleGrants(signer, milestoneUIDs, data, callback) {
68
+ // Validate that all milestones are completed
69
+ if (!this.completed)
70
+ throw new SchemaError_1.AttestationError("ATTEST_ERROR", "Milestone is not completed");
71
+ const schema = this.schema.gap.findSchema("MilestoneCompleted");
72
+ if (this.schema.isJsonSchema()) {
73
+ schema.setValue("json", JSON.stringify({
74
+ type: "approved",
75
+ ...data,
76
+ }));
77
+ }
78
+ else {
79
+ schema.setValue("type", "approved");
80
+ schema.setValue("reason", data?.reason || "");
81
+ schema.setValue("proofOfWork", data?.proofOfWork || "");
82
+ }
83
+ // Create approval attestations for each milestone
84
+ const approvalPayloads = [];
85
+ for (const milestoneUID of milestoneUIDs) {
86
+ const approved = new attestations_1.MilestoneCompleted({
87
+ data: {
88
+ type: "approved",
89
+ ...data,
90
+ },
91
+ refUID: milestoneUID,
92
+ schema,
93
+ recipient: this.recipient,
94
+ });
95
+ // Add approval to the payload
96
+ approvalPayloads.push([
97
+ approved,
98
+ await approved.payloadFor(0), // Index doesn't matter for approval
99
+ ]);
100
+ }
101
+ // Attest all approvals at once
102
+ const result = await GapContract_1.GapContract.multiAttest(signer, approvalPayloads.map((p) => p[1]), callback);
103
+ // Save the first approval to this milestone instance
104
+ if (result.uids.length > 0) {
105
+ this.approved = new attestations_1.MilestoneCompleted({
106
+ data: {
107
+ type: "approved",
108
+ ...data,
109
+ },
110
+ refUID: milestoneUIDs[0],
111
+ uid: result.uids[0],
112
+ schema,
113
+ recipient: this.recipient,
114
+ });
115
+ }
116
+ return result;
117
+ }
48
118
  /**
49
119
  * Revokes the approved status of the milestone. If the milestone is not approved,
50
120
  * it will throw an error.
@@ -99,6 +169,42 @@ class Milestone extends Attestation_1.Attestation {
99
169
  ]);
100
170
  return { tx, uids };
101
171
  }
172
+ /**
173
+ * Revokes multiple milestone attestations at once.
174
+ * This method can be used to revoke multiple milestone attestations in a single transaction.
175
+ *
176
+ * @param signer - The signer to use for revocation
177
+ * @param attestationsToRevoke - Array of objects containing schemaId and uid of attestations to revoke
178
+ * @param callback - Optional callback function for status updates
179
+ * @returns Promise with transaction and UIDs of revoked attestations
180
+ */
181
+ async revokeMultipleAttestations(signer, attestationsToRevoke, callback) {
182
+ if (attestationsToRevoke.length === 0) {
183
+ throw new SchemaError_1.AttestationError("ATTEST_ERROR", "No attestations specified for revocation");
184
+ }
185
+ // Group the attestations by schema ID
186
+ const groupedAttestations = attestationsToRevoke.reduce((acc, { schemaId, uid }) => {
187
+ if (!acc[schemaId]) {
188
+ acc[schemaId] = [];
189
+ }
190
+ acc[schemaId].push(uid);
191
+ return acc;
192
+ }, {});
193
+ // Convert to the format expected by GapContract.multiRevoke
194
+ const revocationPayload = Object.entries(groupedAttestations).map(([schemaId, uids]) => ({
195
+ schema: schemaId,
196
+ data: uids.map((uid) => ({
197
+ uid,
198
+ value: 0n, // EAS contract requires a value field as BigInt
199
+ })),
200
+ }));
201
+ // Use GapContract.multiRevoke directly with the correct payload format
202
+ const result = await GapContract_1.GapContract.multiRevoke(signer, revocationPayload);
203
+ if (callback) {
204
+ callback("confirmed");
205
+ }
206
+ return result;
207
+ }
102
208
  /**
103
209
  * Marks a milestone as completed. If the milestone is already completed,
104
210
  * it will throw an error.
@@ -130,6 +236,87 @@ class Milestone extends Attestation_1.Attestation {
130
236
  });
131
237
  return { tx, uids };
132
238
  }
239
+ /**
240
+ * Marks a milestone as completed across multiple grants. If the milestone is already completed,
241
+ * it will throw an error.
242
+ * @param signer - The signer to use for attestation
243
+ * @param grantIndices - Array of grant indices to attest this milestone to, or array of milestone UIDs
244
+ * @param data - Optional completion data
245
+ * @param callback - Optional callback function for status updates
246
+ * @returns Promise with transaction and UIDs
247
+ */
248
+ async completeForMultipleGrants(signer, grantIndicesOrMilestoneUIDs = [0], data, callback) {
249
+ // Check if we're dealing with UIDs instead of indices
250
+ const isUids = grantIndicesOrMilestoneUIDs.length > 0 &&
251
+ typeof grantIndicesOrMilestoneUIDs[0] === "string";
252
+ let milestoneUIDs = [];
253
+ if (isUids) {
254
+ // We already have milestone UIDs
255
+ milestoneUIDs = grantIndicesOrMilestoneUIDs;
256
+ }
257
+ else {
258
+ // First attest the milestone to multiple grants if not already attested
259
+ const attestResult = await this.attestToMultipleGrants(signer, grantIndicesOrMilestoneUIDs, callback);
260
+ milestoneUIDs = attestResult.uids;
261
+ }
262
+ // Now complete the milestone for each attested milestone
263
+ const schema = this.schema.gap.findSchema("MilestoneCompleted");
264
+ if (this.schema.isJsonSchema()) {
265
+ schema.setValue("json", JSON.stringify({
266
+ type: "completed",
267
+ ...data,
268
+ }));
269
+ }
270
+ else {
271
+ schema.setValue("type", "completed");
272
+ schema.setValue("reason", data?.reason || "");
273
+ schema.setValue("proofOfWork", data?.proofOfWork || "");
274
+ }
275
+ // Create completion attestations for each milestone
276
+ const completionPayloads = [];
277
+ for (let i = 0; i < milestoneUIDs.length; i++) {
278
+ const milestoneUID = milestoneUIDs[i];
279
+ // Only set this.uid if we're dealing with indices and need to update the current milestone
280
+ if (!isUids) {
281
+ this.uid = milestoneUID; // Set the current UID to the milestone being completed
282
+ }
283
+ const completed = new attestations_1.MilestoneCompleted({
284
+ data: {
285
+ type: "completed",
286
+ ...data,
287
+ },
288
+ refUID: milestoneUID,
289
+ schema,
290
+ recipient: this.recipient,
291
+ });
292
+ // Add completed status to the payload
293
+ completionPayloads.push([completed, await completed.payloadFor(i)]);
294
+ }
295
+ // Attest all completions at once
296
+ const completionResult = await GapContract_1.GapContract.multiAttest(signer, completionPayloads.map((p) => p[1]), callback);
297
+ // Save the first completion to this milestone instance
298
+ if (completionResult.uids.length > 0 && !isUids) {
299
+ this.completed = new attestations_1.MilestoneCompleted({
300
+ data: {
301
+ type: "completed",
302
+ ...data,
303
+ },
304
+ refUID: milestoneUIDs[0],
305
+ uid: completionResult.uids[0],
306
+ schema,
307
+ recipient: this.recipient,
308
+ });
309
+ }
310
+ return isUids
311
+ ? completionResult // If we're using UIDs directly, just return completion result
312
+ : {
313
+ tx: [
314
+ ...(milestoneUIDs.length ? [{ hash: "" }] : []),
315
+ ...completionResult.tx,
316
+ ],
317
+ uids: [...milestoneUIDs, ...completionResult.uids],
318
+ };
319
+ }
133
320
  /**
134
321
  * Revokes the completed status of the milestone. If the milestone is not completed,
135
322
  * it will throw an error.
@@ -176,6 +363,92 @@ class Milestone extends Attestation_1.Attestation {
176
363
  }
177
364
  return payload.slice(currentPayload.length, payload.length);
178
365
  }
366
+ /**
367
+ * Creates the payload for a multi-attestation across multiple grants.
368
+ *
369
+ * This method allows for the same milestone to be attested to multiple grants
370
+ * in a single transaction.
371
+ *
372
+ * @param currentPayload - Current payload to append to
373
+ * @param grantIndices - Array of grant indices to attest this milestone to
374
+ * @returns The multi-attest payload with all grant attestations
375
+ */
376
+ async multiGrantAttestPayload(currentPayload = [], grantIndices = [0]) {
377
+ this.assertPayload();
378
+ const payload = [...currentPayload];
379
+ const milestoneIndices = [];
380
+ // Create milestone attestation for each grant
381
+ for (const grantIdx of grantIndices) {
382
+ const milestoneIdx = payload.push([this, await this.payloadFor(grantIdx)]) - 1;
383
+ milestoneIndices.push(milestoneIdx);
384
+ }
385
+ // Add completed status if exists for each milestone
386
+ if (this.completed) {
387
+ for (const milestoneIdx of milestoneIndices) {
388
+ payload.push([
389
+ this.completed,
390
+ await this.completed.payloadFor(milestoneIdx),
391
+ ]);
392
+ }
393
+ }
394
+ // Add verifications if exist for each milestone
395
+ if (this.verified.length > 0) {
396
+ for (const milestoneIdx of milestoneIndices) {
397
+ await Promise.all(this.verified.map(async (m) => {
398
+ const payloadForMilestone = await m.payloadFor(milestoneIdx);
399
+ if (Array.isArray(payloadForMilestone)) {
400
+ payloadForMilestone.forEach((item) => payload.push(item));
401
+ }
402
+ }));
403
+ }
404
+ }
405
+ return payload.slice(currentPayload.length, payload.length);
406
+ }
407
+ /**
408
+ * Attests this milestone to multiple grants in a single transaction.
409
+ *
410
+ * @param signer - The signer to use for attestation
411
+ * @param grantIndices - Array of grant indices to attest this milestone to, or array of grant UIDs
412
+ * @param callback - Optional callback function for status updates
413
+ * @returns Promise with transaction and UIDs
414
+ */
415
+ async attestToMultipleGrants(signer, grantIndices = [0], callback) {
416
+ this.assertPayload();
417
+ // Check if we're dealing with Hex UIDs instead of indices
418
+ const isUids = grantIndices.length > 0 && typeof grantIndices[0] === "string";
419
+ if (isUids) {
420
+ // Direct approach - create individual milestone instances for each grant UID
421
+ const grantUIDs = grantIndices;
422
+ const allPayloads = [];
423
+ for (const grantUID of grantUIDs) {
424
+ // Create a new milestone for each grant with direct reference
425
+ const grantMilestone = new Milestone({
426
+ schema: this.schema,
427
+ recipient: this.recipient,
428
+ data: this.data,
429
+ refUID: grantUID,
430
+ });
431
+ // Generate payload for this grant
432
+ const payload = await grantMilestone.multiAttestPayload();
433
+ // Add each item from payload to allPayloads
434
+ payload.forEach((item) => allPayloads.push(item));
435
+ }
436
+ // Attest all milestones in a single transaction
437
+ const result = await GapContract_1.GapContract.multiAttest(signer, allPayloads.map((p) => p[1]), callback);
438
+ return result;
439
+ }
440
+ else {
441
+ // Original implementation using grantIndices
442
+ const payload = await this.multiGrantAttestPayload([], grantIndices);
443
+ const { uids, tx } = await GapContract_1.GapContract.multiAttest(signer, payload.map((p) => p[1]), callback);
444
+ if (Array.isArray(uids)) {
445
+ uids.forEach((uid, index) => {
446
+ payload[index][0].uid = uid;
447
+ });
448
+ }
449
+ return { tx, uids };
450
+ }
451
+ }
179
452
  /**
180
453
  * @inheritdoc
181
454
  */
@@ -318,5 +591,67 @@ class Milestone extends Attestation_1.Attestation {
318
591
  }));
319
592
  return { tx, uids };
320
593
  }
594
+ /**
595
+ * Verifies this milestone across multiple grants. If the milestones are not completed,
596
+ * it will throw an error.
597
+ * @param signer - The signer to use for attestation
598
+ * @param milestoneUIDs - Array of milestone UIDs to verify
599
+ * @param data - Optional verification data
600
+ * @param callback - Optional callback function for status updates
601
+ * @returns Promise with transaction and UIDs
602
+ */
603
+ async verifyMultipleGrants(signer, milestoneUIDs, data, callback) {
604
+ // Validate that all milestones are completed
605
+ if (!this.completed)
606
+ throw new SchemaError_1.AttestationError("ATTEST_ERROR", "Milestone is not completed");
607
+ const schema = this.schema.gap.findSchema("MilestoneCompleted");
608
+ if (this.schema.isJsonSchema()) {
609
+ schema.setValue("json", JSON.stringify({
610
+ type: "verified",
611
+ ...data,
612
+ }));
613
+ }
614
+ else {
615
+ schema.setValue("type", "verified");
616
+ schema.setValue("reason", data?.reason || "");
617
+ schema.setValue("proofOfWork", data?.proofOfWork || "");
618
+ }
619
+ // Create verification attestations for each milestone
620
+ const verificationPayloads = [];
621
+ for (const milestoneUID of milestoneUIDs) {
622
+ const verified = new attestations_1.MilestoneCompleted({
623
+ data: {
624
+ type: "verified",
625
+ ...data,
626
+ },
627
+ refUID: milestoneUID,
628
+ schema,
629
+ recipient: this.recipient,
630
+ });
631
+ // Add verification to the payload
632
+ verificationPayloads.push([
633
+ verified,
634
+ await verified.payloadFor(0), // Index doesn't matter for verification
635
+ ]);
636
+ }
637
+ // Attest all verifications at once
638
+ const result = await GapContract_1.GapContract.multiAttest(signer, verificationPayloads.map((p) => p[1]), callback);
639
+ // Save the verifications to this milestone instance
640
+ if (result.uids.length > 0) {
641
+ for (let i = 0; i < result.uids.length; i++) {
642
+ this.verified.push(new attestations_1.MilestoneCompleted({
643
+ data: {
644
+ type: "verified",
645
+ ...data,
646
+ },
647
+ refUID: milestoneUIDs[i],
648
+ uid: result.uids[i],
649
+ schema,
650
+ recipient: this.recipient,
651
+ }));
652
+ }
653
+ }
654
+ return result;
655
+ }
321
656
  }
322
657
  exports.Milestone = Milestone;
@@ -206,13 +206,14 @@ class Project extends Attestation_1.Attestation {
206
206
  this.members.splice(0, this.members.length);
207
207
  }
208
208
  static from(attestations, network) {
209
+ const allSchemas = new AllGapSchemas_1.AllGapSchemas();
209
210
  return attestations.map((attestation) => {
210
211
  const project = new Project({
211
212
  ...attestation,
212
213
  data: {
213
214
  project: true,
214
215
  },
215
- schema: new AllGapSchemas_1.AllGapSchemas().findSchema("Project", consts_1.chainIdToNetwork[attestation.chainID]),
216
+ schema: allSchemas.findSchema("Project", consts_1.chainIdToNetwork[attestation.chainID]),
216
217
  chainID: attestation.chainID,
217
218
  });
218
219
  if (attestation.details) {
@@ -222,7 +223,7 @@ class Project extends Attestation_1.Attestation {
222
223
  data: {
223
224
  ...details.data,
224
225
  },
225
- schema: new AllGapSchemas_1.AllGapSchemas().findSchema("ProjectDetails", consts_1.chainIdToNetwork[attestation.chainID]),
226
+ schema: allSchemas.findSchema("ProjectDetails", consts_1.chainIdToNetwork[attestation.chainID]),
226
227
  chainID: attestation.chainID,
227
228
  });
228
229
  project.details.links = details.data.links || [];
@@ -241,7 +242,7 @@ class Project extends Attestation_1.Attestation {
241
242
  data: {
242
243
  memberOf: true,
243
244
  },
244
- schema: new AllGapSchemas_1.AllGapSchemas().findSchema("MemberOf", consts_1.chainIdToNetwork[attestation.chainID]),
245
+ schema: allSchemas.findSchema("MemberOf", consts_1.chainIdToNetwork[attestation.chainID]),
245
246
  chainID: attestation.chainID,
246
247
  });
247
248
  if (m.details) {
@@ -251,7 +252,7 @@ class Project extends Attestation_1.Attestation {
251
252
  data: {
252
253
  ...details.data,
253
254
  },
254
- schema: new AllGapSchemas_1.AllGapSchemas().findSchema("MemberDetails", consts_1.chainIdToNetwork[attestation.chainID]),
255
+ schema: allSchemas.findSchema("MemberDetails", consts_1.chainIdToNetwork[attestation.chainID]),
255
256
  chainID: attestation.chainID,
256
257
  });
257
258
  }
@@ -280,7 +281,7 @@ class Project extends Attestation_1.Attestation {
280
281
  data: {
281
282
  ...pi.data,
282
283
  },
283
- schema: new AllGapSchemas_1.AllGapSchemas().findSchema("ProjectDetails", consts_1.chainIdToNetwork[attestation.chainID]),
284
+ schema: allSchemas.findSchema("ProjectDetails", consts_1.chainIdToNetwork[attestation.chainID]),
284
285
  chainID: attestation.chainID,
285
286
  });
286
287
  return endorsement;
package/core/consts.d.ts CHANGED
@@ -13,6 +13,7 @@ export declare const chainIdToNetwork: {
13
13
  42220: string;
14
14
  1328: string;
15
15
  1329: string;
16
+ 1135: string;
16
17
  };
17
18
  export declare const nullRef = "0x0000000000000000000000000000000000000000000000000000000000000000";
18
19
  export declare const nullResolver = "0x0000000000000000000000000000000000000000";
package/core/consts.js CHANGED
@@ -26,6 +26,7 @@ exports.chainIdToNetwork = {
26
26
  42220: "celo",
27
27
  1328: "sei-testnet",
28
28
  1329: "sei",
29
+ 1135: "lisk",
29
30
  };
30
31
  exports.nullRef = "0x0000000000000000000000000000000000000000000000000000000000000000";
31
32
  // TODO: Remove null resolver and change usage to zero address
@@ -396,6 +397,34 @@ exports.Networks = {
396
397
  ContributorProfile: "0x"
397
398
  },
398
399
  },
400
+ lisk: {
401
+ chainId: 1135,
402
+ url: "https://arbitrum.easscan.org/graphql",
403
+ rpcUrl: "https://arb-mainnet.g.alchemy.com/v2/okcKBSKXvLuSCbas6QWGvKuh-IcHHSOr",
404
+ contracts: {
405
+ eas: "0x4200000000000000000000000000000000000021",
406
+ schema: "0x4200000000000000000000000000000000000020",
407
+ multicall: "0x28BE0b0515be8BB8822aF1467A6613795E74717b",
408
+ projectResolver: "0x6dC1D6b864e8BEf815806f9e4677123496e12026",
409
+ communityResolver: "0xfddb660F2F1C27d219372210745BB9f73431856E",
410
+ donations: "0x28BE0b0515be8BB8822aF1467A6613795E74717b",
411
+ airdropNFT: null,
412
+ },
413
+ schemas: {
414
+ Community: "0x3c2231024f4f17f3718b5bd9ed9ff29cc323dea5449f9ceba11a9888bfbdd0e1",
415
+ Details: "0x16bfe4783b7a9c743c401222c56a07ecb77ed42afc84b61ff1f62f5936c0b9d7",
416
+ Grant: "0xea02ab33f9f4c92ba02c9bb21614b7410b98c940a0d8eb8ad3a20204d8b4bda5",
417
+ GrantVerified: "0xd88faddf8df50a07a4130fbe2131354831261440b2ca695c4e9b8f2ca9985346",
418
+ MemberOf: "0x5f430aec9d04f0dcb3729775c5dfe10752e436469a7607f8c64ae44ef996e477",
419
+ MilestoneApproved: "0xd88faddf8df50a07a4130fbe2131354831261440b2ca695c4e9b8f2ca9985346",
420
+ MilestoneCompleted: "0xd88faddf8df50a07a4130fbe2131354831261440b2ca695c4e9b8f2ca9985346",
421
+ GrantUpdateStatus: "0xd88faddf8df50a07a4130fbe2131354831261440b2ca695c4e9b8f2ca9985346",
422
+ Project: "0xf3f753b41e04d1052b5a5ec7624d1dfdb6c2da288a985120e477ddbcac071022",
423
+ ProjectUpdateStatus: "0xd88faddf8df50a07a4130fbe2131354831261440b2ca695c4e9b8f2ca9985346",
424
+ ProjectMilestoneStatus: "0xd88faddf8df50a07a4130fbe2131354831261440b2ca695c4e9b8f2ca9985346",
425
+ ContributorProfile: "0x80f0701853e862d920f87e8ae5b359a1625ad417a9523af2ed12bc3504b04088"
426
+ },
427
+ },
399
428
  };
400
429
  const DetailsSchema = [{ type: "string", name: "json", value: null }];
401
430
  /**
package/core/types.d.ts CHANGED
@@ -30,7 +30,7 @@ export interface AttestArgs<T = unknown> {
30
30
  export type TSchemaName = "Community" | "CommunityDetails" | "Grant" | "GrantDetails" | "GrantVerified" | "MemberOf" | "MemberDetails" | "Milestone" | "MilestoneCompleted" | "MilestoneApproved" | "Project" | "ProjectDetails" | "Details" | "ProjectImpact" | "ProjectUpdate" | "ProjectUpdateStatus" | "ProjectPointer" | "GrantUpdate" | "GrantUpdateStatus" | "ProjectEndorsement" | "ProjectMilestone" | "ProjectMilestoneStatus" | "ContributorProfile";
31
31
  export type TResolvedSchemaNames = "Community" | "Grant" | "GrantVerified" | "MemberOf" | "MilestoneCompleted" | "MilestoneApproved" | "Project" | "Details" | "ProjectUpdateStatus" | "GrantUpdateStatus" | "ProjectUpdateStatus" | "ProjectMilestoneStatus" | "ContributorProfile";
32
32
  export type TExternalLink = "twitter" | "github" | "website" | "linkedin" | "discord" | "pitchDeck" | "demoVideo" | "farcaster";
33
- export type TNetwork = "optimism" | "celo" | "optimism-sepolia" | "arbitrum" | "sepolia" | "sei" | "sei-testnet" | "base-sepolia";
33
+ export type TNetwork = "optimism" | "celo" | "optimism-sepolia" | "arbitrum" | "sepolia" | "sei" | "sei-testnet" | "base-sepolia" | "lisk";
34
34
  /**
35
35
  * Generic GAP Facade interface.
36
36
  * This supplies the GAP class with the necessary properties.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.4.11",
6
+ "version": "0.4.12",
7
7
  "description": "Simple and easy interface between EAS and Karma GAP.",
8
8
  "main": "./index.js",
9
9
  "author": "KarmaHQ",
@@ -16,6 +16,8 @@
16
16
  "scripts": {
17
17
  "deploy": "npx ts-node ./core/scripts/deploy.ts",
18
18
  "csv-upload": "npx ts-node ./csv-upload/scripts/run.ts",
19
+ "test-file": "npx ts-node ./test-file-indexer-api.ts",
20
+ "test-milestone": "npx ts-node ./milestone-workflow-example.ts",
19
21
  "publish-npm": "npm version patch && tsc && cd .dist && npm publish --scope=@show-karma/karma-gap-sdk --access public"
20
22
  },
21
23
  "dependencies": {