@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.
- package/.cursorrules +43 -0
- package/core/abi/AirdropNFT.json +1 -1
- package/core/abi/Allo.json +860 -860
- package/core/abi/AlloRegistry.json +578 -578
- package/core/abi/CommunityResolverABI.json +506 -506
- package/core/abi/Donations.json +251 -251
- package/core/abi/EAS.json +1 -1
- package/core/abi/MultiAttester.json +746 -746
- package/core/abi/ProjectResolver.json +574 -574
- package/core/abi/SchemaRegistry.json +1 -1
- package/core/abi/index.ts +21 -0
- package/core/class/AllGapSchemas.ts +21 -0
- package/core/class/Attestation.ts +429 -0
- package/core/class/Fetcher.ts +224 -0
- package/core/class/GAP.ts +481 -0
- package/core/class/GapSchema.ts +93 -0
- package/core/class/Gelato/{Gelato.js → Gelato.ts} +23 -0
- package/core/class/GrantProgramRegistry/Allo.ts +188 -0
- package/core/class/GrantProgramRegistry/AlloRegistry.ts +101 -0
- package/core/class/GraphQL/AxiosGQL.ts +29 -0
- package/core/class/GraphQL/EASClient.ts +34 -0
- package/core/class/GraphQL/GapEasClient.ts +869 -0
- package/core/class/Schema.ts +659 -0
- package/core/class/SchemaError.ts +42 -0
- package/core/class/contract/GapContract.ts +457 -0
- package/core/class/entities/Community.ts +148 -0
- package/core/class/entities/ContributorProfile.ts +108 -0
- package/core/class/entities/Grant.ts +321 -0
- package/core/class/entities/GrantUpdate.ts +187 -0
- package/core/class/entities/MemberOf.ts +52 -0
- package/core/class/entities/Milestone.ts +898 -0
- package/core/class/entities/Project.ts +672 -0
- package/core/class/entities/ProjectImpact.ts +170 -0
- package/core/class/entities/ProjectMilestone.ts +254 -0
- package/core/class/entities/ProjectPointer.ts +39 -0
- package/core/class/entities/ProjectUpdate.ts +176 -0
- package/core/class/entities/Track.ts +32 -0
- package/core/class/karma-indexer/GapIndexerClient.ts +383 -0
- package/core/class/karma-indexer/api/GapIndexerApi.ts +446 -0
- package/core/class/karma-indexer/api/types.ts +313 -0
- package/core/class/remote-storage/IpfsStorage.ts +76 -0
- package/core/class/remote-storage/RemoteStorage.ts +65 -0
- package/core/class/types/allo.ts +93 -0
- package/core/class/types/attestations.ts +223 -0
- package/core/consts.ts +775 -0
- package/core/scripts/create-grant.ts +102 -0
- package/core/scripts/create-program.ts +43 -0
- package/core/scripts/create-schemas.ts +65 -0
- package/core/scripts/deploy.ts +65 -0
- package/core/scripts/index.ts +1 -0
- package/core/scripts/milestone-multi-grants.ts +125 -0
- package/core/shared/types.ts +13 -0
- package/core/types.ts +224 -0
- package/core/utils/gelato/send-gelato-txn.ts +114 -0
- package/core/utils/gelato/sponsor-handler.ts +77 -0
- package/core/utils/gelato/watch-gelato-txn.ts +67 -0
- package/core/utils/get-date.ts +3 -0
- package/core/utils/get-ipfs-data.ts +13 -0
- package/core/utils/get-web3-provider.ts +18 -0
- package/core/utils/gql-queries.ts +133 -0
- package/core/utils/map-filter.ts +21 -0
- package/core/utils/serialize-bigint.ts +7 -0
- package/core/utils/to-unix.ts +18 -0
- package/create-community-example.ts +119 -0
- package/csv-upload/README.md +74 -0
- package/csv-upload/config.ts +41 -0
- package/csv-upload/example.csv +2 -0
- package/csv-upload/keys.example.json +8 -0
- package/csv-upload/scripts/run.ts +417 -0
- package/csv-upload/types.ts +39 -0
- package/docs/.gitkeep +0 -0
- package/docs/images/attestation-architecture.png +0 -0
- package/docs/images/dfd-get-projects.png +0 -0
- package/gap-schema.yaml +155 -0
- package/milestone-workflow-example.ts +353 -0
- package/package.json +45 -39
- package/readme.md +872 -0
- package/schemas/.gitkeep +0 -0
- package/schemas/GAP-schemas-1692135812877.json +33 -0
- package/test-file-indexer-api.ts +25 -0
- package/tsconfig.json +26 -0
- package/core/abi/index.d.ts +0 -1114
- package/core/abi/index.js +0 -26
- package/core/class/AllGapSchemas.d.ts +0 -9
- package/core/class/AllGapSchemas.js +0 -19
- package/core/class/Attestation.d.ts +0 -173
- package/core/class/Attestation.js +0 -333
- package/core/class/Fetcher.d.ts +0 -175
- package/core/class/Fetcher.js +0 -13
- package/core/class/GAP.d.ts +0 -254
- package/core/class/GAP.js +0 -289
- package/core/class/GapSchema.d.ts +0 -34
- package/core/class/GapSchema.js +0 -62
- package/core/class/GrantProgramRegistry/Allo.d.ts +0 -17
- package/core/class/GrantProgramRegistry/Allo.js +0 -137
- package/core/class/GrantProgramRegistry/AlloRegistry.d.ts +0 -15
- package/core/class/GrantProgramRegistry/AlloRegistry.js +0 -70
- package/core/class/GraphQL/AxiosGQL.d.ts +0 -6
- package/core/class/GraphQL/AxiosGQL.js +0 -25
- package/core/class/GraphQL/EASClient.d.ts +0 -16
- package/core/class/GraphQL/EASClient.js +0 -26
- package/core/class/GraphQL/GapEasClient.d.ts +0 -71
- package/core/class/GraphQL/GapEasClient.js +0 -451
- package/core/class/GraphQL/index.js +0 -19
- package/core/class/Schema.d.ts +0 -233
- package/core/class/Schema.js +0 -488
- package/core/class/SchemaError.d.ts +0 -30
- package/core/class/SchemaError.js +0 -39
- package/core/class/contract/GapContract.d.ts +0 -102
- package/core/class/contract/GapContract.js +0 -285
- package/core/class/entities/Community.d.ts +0 -34
- package/core/class/entities/Community.js +0 -109
- package/core/class/entities/ContributorProfile.d.ts +0 -41
- package/core/class/entities/ContributorProfile.js +0 -69
- package/core/class/entities/Grant.d.ts +0 -54
- package/core/class/entities/Grant.js +0 -223
- package/core/class/entities/GrantUpdate.d.ts +0 -40
- package/core/class/entities/GrantUpdate.js +0 -114
- package/core/class/entities/MemberOf.d.ts +0 -11
- package/core/class/entities/MemberOf.js +0 -33
- package/core/class/entities/Milestone.d.ts +0 -168
- package/core/class/entities/Milestone.js +0 -657
- package/core/class/entities/Project.d.ts +0 -92
- package/core/class/entities/Project.js +0 -418
- package/core/class/entities/ProjectImpact.d.ts +0 -50
- package/core/class/entities/ProjectImpact.js +0 -112
- package/core/class/entities/ProjectMilestone.d.ts +0 -60
- package/core/class/entities/ProjectMilestone.js +0 -174
- package/core/class/entities/ProjectPointer.d.ts +0 -12
- package/core/class/entities/ProjectPointer.js +0 -22
- package/core/class/entities/ProjectUpdate.d.ts +0 -50
- package/core/class/entities/ProjectUpdate.js +0 -110
- package/core/class/entities/Track.d.ts +0 -16
- package/core/class/entities/Track.js +0 -21
- package/core/class/entities/index.js +0 -26
- package/core/class/index.js +0 -26
- package/core/class/karma-indexer/GapIndexerClient.d.ts +0 -66
- package/core/class/karma-indexer/GapIndexerClient.js +0 -207
- package/core/class/karma-indexer/api/GapIndexerApi.d.ts +0 -73
- package/core/class/karma-indexer/api/GapIndexerApi.js +0 -256
- package/core/class/karma-indexer/api/types.d.ts +0 -295
- package/core/class/karma-indexer/api/types.js +0 -2
- package/core/class/remote-storage/IpfsStorage.d.ts +0 -23
- package/core/class/remote-storage/IpfsStorage.js +0 -56
- package/core/class/remote-storage/RemoteStorage.d.ts +0 -41
- package/core/class/remote-storage/RemoteStorage.js +0 -38
- package/core/class/types/allo.d.ts +0 -78
- package/core/class/types/allo.js +0 -2
- package/core/class/types/attestations.d.ts +0 -168
- package/core/class/types/attestations.js +0 -66
- package/core/consts.d.ts +0 -48
- package/core/consts.js +0 -641
- package/core/index.js +0 -24
- package/core/shared/types.d.ts +0 -6
- package/core/shared/types.js +0 -2
- package/core/types.d.ts +0 -131
- package/core/types.js +0 -13
- package/core/utils/gelato/index.js +0 -19
- package/core/utils/gelato/send-gelato-txn.d.ts +0 -55
- package/core/utils/gelato/send-gelato-txn.js +0 -100
- package/core/utils/gelato/sponsor-handler.d.ts +0 -9
- package/core/utils/gelato/sponsor-handler.js +0 -60
- package/core/utils/gelato/watch-gelato-txn.d.ts +0 -7
- package/core/utils/gelato/watch-gelato-txn.js +0 -63
- package/core/utils/get-date.d.ts +0 -1
- package/core/utils/get-date.js +0 -7
- package/core/utils/get-ipfs-data.d.ts +0 -1
- package/core/utils/get-ipfs-data.js +0 -20
- package/core/utils/get-web3-provider.d.ts +0 -2
- package/core/utils/get-web3-provider.js +0 -18
- package/core/utils/gql-queries.d.ts +0 -12
- package/core/utils/gql-queries.js +0 -90
- package/core/utils/index.js +0 -23
- package/core/utils/map-filter.d.ts +0 -8
- package/core/utils/map-filter.js +0 -20
- package/core/utils/serialize-bigint.d.ts +0 -1
- package/core/utils/serialize-bigint.js +0 -8
- package/core/utils/to-unix.d.ts +0 -1
- package/core/utils/to-unix.js +0 -25
- package/index.js +0 -17
- /package/core/class/GraphQL/{index.d.ts → index.ts} +0 -0
- /package/core/class/entities/{index.d.ts → index.ts} +0 -0
- /package/core/class/{index.d.ts → index.ts} +0 -0
- /package/core/{index.d.ts → index.ts} +0 -0
- /package/core/utils/gelato/{index.d.ts → index.ts} +0 -0
- /package/core/utils/{index.d.ts → index.ts} +0 -0
- /package/{core/class/Gelato/Gelato.d.ts → csv-upload/.gitkeep} +0 -0
- /package/{index.d.ts → index.ts} +0 -0
|
@@ -0,0 +1,898 @@
|
|
|
1
|
+
import { Transaction } from "ethers";
|
|
2
|
+
import { chainIdToNetwork } from "../../consts";
|
|
3
|
+
import {
|
|
4
|
+
Hex,
|
|
5
|
+
MultiAttestPayload,
|
|
6
|
+
MultiRevokeArgs,
|
|
7
|
+
SignerOrProvider,
|
|
8
|
+
TNetwork,
|
|
9
|
+
} from "../../types";
|
|
10
|
+
import { AllGapSchemas } from "../AllGapSchemas";
|
|
11
|
+
import { Attestation } from "../Attestation";
|
|
12
|
+
import { GAP } from "../GAP";
|
|
13
|
+
import { GapSchema } from "../GapSchema";
|
|
14
|
+
import { AttestationError } from "../SchemaError";
|
|
15
|
+
import { GapContract } from "../contract/GapContract";
|
|
16
|
+
import { IMilestoneResponse } from "../karma-indexer/api/types";
|
|
17
|
+
import {
|
|
18
|
+
AttestationWithTx,
|
|
19
|
+
MilestoneCompleted,
|
|
20
|
+
IMilestoneCompleted,
|
|
21
|
+
} from "../types/attestations";
|
|
22
|
+
|
|
23
|
+
interface _Milestone extends Milestone {}
|
|
24
|
+
|
|
25
|
+
export interface IMilestone {
|
|
26
|
+
title: string;
|
|
27
|
+
startsAt?: number;
|
|
28
|
+
endsAt: number;
|
|
29
|
+
description: string;
|
|
30
|
+
type?: string;
|
|
31
|
+
priority?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Milestone class represents a milestone that can be attested to one or multiple grants.
|
|
36
|
+
*
|
|
37
|
+
* It provides methods to:
|
|
38
|
+
* - Create, complete, approve, reject, and verify milestones
|
|
39
|
+
* - Attest a milestone to a single grant
|
|
40
|
+
* - Attest a milestone to multiple grants in a single transaction
|
|
41
|
+
* - Complete, approve, and verify milestones across multiple grants
|
|
42
|
+
* - Revoke multiple milestone attestations at once
|
|
43
|
+
*/
|
|
44
|
+
export class Milestone extends Attestation<IMilestone> implements IMilestone {
|
|
45
|
+
title: string;
|
|
46
|
+
startsAt?: number;
|
|
47
|
+
endsAt: number;
|
|
48
|
+
description: string;
|
|
49
|
+
completed: MilestoneCompleted;
|
|
50
|
+
approved: MilestoneCompleted;
|
|
51
|
+
rejected: MilestoneCompleted;
|
|
52
|
+
verified: MilestoneCompleted[] = [];
|
|
53
|
+
type = "milestone";
|
|
54
|
+
priority?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Approves this milestone. If the milestone is not completed or already approved,
|
|
57
|
+
* it will throw an error.
|
|
58
|
+
* @param signer
|
|
59
|
+
* @param reason
|
|
60
|
+
*/
|
|
61
|
+
async approve(
|
|
62
|
+
signer: SignerOrProvider,
|
|
63
|
+
data?: IMilestoneCompleted,
|
|
64
|
+
callback?: Function
|
|
65
|
+
) {
|
|
66
|
+
if (!this.completed)
|
|
67
|
+
throw new AttestationError("ATTEST_ERROR", "Milestone is not completed");
|
|
68
|
+
|
|
69
|
+
const schema = this.schema.gap.findSchema("MilestoneCompleted");
|
|
70
|
+
if (this.schema.isJsonSchema()) {
|
|
71
|
+
schema.setValue(
|
|
72
|
+
"json",
|
|
73
|
+
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
|
+
await this.attestStatus(signer, schema, callback);
|
|
84
|
+
|
|
85
|
+
this.approved = new MilestoneCompleted({
|
|
86
|
+
data: {
|
|
87
|
+
type: "approved",
|
|
88
|
+
reason: data?.reason || "",
|
|
89
|
+
},
|
|
90
|
+
refUID: this.uid,
|
|
91
|
+
schema: schema,
|
|
92
|
+
recipient: this.recipient,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Approves this milestone across multiple grants. If the milestones are not completed,
|
|
98
|
+
* it will throw an error.
|
|
99
|
+
* @param signer - The signer to use for attestation
|
|
100
|
+
* @param milestoneUIDs - Array of milestone UIDs to approve
|
|
101
|
+
* @param data - Optional approval data
|
|
102
|
+
* @param callback - Optional callback function for status updates
|
|
103
|
+
* @returns Promise with transaction and UIDs
|
|
104
|
+
*/
|
|
105
|
+
async approveMultipleGrants(
|
|
106
|
+
signer: SignerOrProvider,
|
|
107
|
+
milestoneUIDs: Hex[],
|
|
108
|
+
data?: IMilestoneCompleted,
|
|
109
|
+
callback?: Function
|
|
110
|
+
): Promise<AttestationWithTx> {
|
|
111
|
+
// Validate that all milestones are completed
|
|
112
|
+
if (!this.completed)
|
|
113
|
+
throw new AttestationError("ATTEST_ERROR", "Milestone is not completed");
|
|
114
|
+
|
|
115
|
+
const schema = this.schema.gap.findSchema("MilestoneCompleted");
|
|
116
|
+
|
|
117
|
+
if (this.schema.isJsonSchema()) {
|
|
118
|
+
schema.setValue(
|
|
119
|
+
"json",
|
|
120
|
+
JSON.stringify({
|
|
121
|
+
type: "approved",
|
|
122
|
+
...data,
|
|
123
|
+
})
|
|
124
|
+
);
|
|
125
|
+
} else {
|
|
126
|
+
schema.setValue("type", "approved");
|
|
127
|
+
schema.setValue("reason", data?.reason || "");
|
|
128
|
+
schema.setValue("proofOfWork", data?.proofOfWork || "");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Create approval attestations for each milestone
|
|
132
|
+
const approvalPayloads: MultiAttestPayload = [];
|
|
133
|
+
|
|
134
|
+
for (const milestoneUID of milestoneUIDs) {
|
|
135
|
+
const approved = new MilestoneCompleted({
|
|
136
|
+
data: {
|
|
137
|
+
type: "approved",
|
|
138
|
+
...data,
|
|
139
|
+
},
|
|
140
|
+
refUID: milestoneUID,
|
|
141
|
+
schema,
|
|
142
|
+
recipient: this.recipient,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Add approval to the payload
|
|
146
|
+
approvalPayloads.push([
|
|
147
|
+
approved,
|
|
148
|
+
await approved.payloadFor(0), // Index doesn't matter for approval
|
|
149
|
+
]);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Attest all approvals at once
|
|
153
|
+
const result = await GapContract.multiAttest(
|
|
154
|
+
signer,
|
|
155
|
+
approvalPayloads.map((p) => p[1]),
|
|
156
|
+
callback
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// Save the first approval to this milestone instance
|
|
160
|
+
if (result.uids.length > 0) {
|
|
161
|
+
this.approved = new MilestoneCompleted({
|
|
162
|
+
data: {
|
|
163
|
+
type: "approved",
|
|
164
|
+
...data,
|
|
165
|
+
},
|
|
166
|
+
refUID: milestoneUIDs[0],
|
|
167
|
+
uid: result.uids[0],
|
|
168
|
+
schema,
|
|
169
|
+
recipient: this.recipient,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Revokes the approved status of the milestone. If the milestone is not approved,
|
|
178
|
+
* it will throw an error.
|
|
179
|
+
* @param signer
|
|
180
|
+
*/
|
|
181
|
+
async revokeApproval(signer: SignerOrProvider) {
|
|
182
|
+
if (!this.approved)
|
|
183
|
+
throw new AttestationError("ATTEST_ERROR", "Milestone is not approved");
|
|
184
|
+
|
|
185
|
+
await this.approved.schema.multiRevoke(signer, [
|
|
186
|
+
{
|
|
187
|
+
schemaId: this.completed.schema.uid,
|
|
188
|
+
uid: this.completed.uid,
|
|
189
|
+
},
|
|
190
|
+
]);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Reject a completed milestone. If the milestone is not completed or already rejected,
|
|
195
|
+
* it will throw an error.
|
|
196
|
+
* @param signer
|
|
197
|
+
* @param reason
|
|
198
|
+
*/
|
|
199
|
+
async reject(signer: SignerOrProvider, reason = "") {
|
|
200
|
+
if (!this.completed)
|
|
201
|
+
throw new AttestationError("ATTEST_ERROR", "Milestone is not completed");
|
|
202
|
+
|
|
203
|
+
const schema = this.schema.gap.findSchema("MilestoneCompleted");
|
|
204
|
+
schema.setValue("type", "rejected");
|
|
205
|
+
schema.setValue("reason", reason);
|
|
206
|
+
await this.attestStatus(signer, schema);
|
|
207
|
+
|
|
208
|
+
this.rejected = new MilestoneCompleted({
|
|
209
|
+
data: {
|
|
210
|
+
type: "rejected",
|
|
211
|
+
reason,
|
|
212
|
+
},
|
|
213
|
+
refUID: this.uid,
|
|
214
|
+
schema: schema,
|
|
215
|
+
recipient: this.recipient,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Revokes the rejected status of the milestone. If the milestone is not rejected,
|
|
221
|
+
* it will throw an error.
|
|
222
|
+
* @param signer
|
|
223
|
+
*/
|
|
224
|
+
async revokeRejection(signer: SignerOrProvider) {
|
|
225
|
+
if (!this.rejected)
|
|
226
|
+
throw new AttestationError("ATTEST_ERROR", "Milestone is not rejected");
|
|
227
|
+
|
|
228
|
+
const { tx, uids } = await this.rejected.schema.multiRevoke(signer, [
|
|
229
|
+
{
|
|
230
|
+
schemaId: this.completed.schema.uid,
|
|
231
|
+
uid: this.completed.uid,
|
|
232
|
+
},
|
|
233
|
+
]);
|
|
234
|
+
return { tx, uids };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Revokes multiple milestone attestations at once.
|
|
239
|
+
* This method can be used to revoke multiple milestone attestations in a single transaction.
|
|
240
|
+
*
|
|
241
|
+
* @param signer - The signer to use for revocation
|
|
242
|
+
* @param attestationsToRevoke - Array of objects containing schemaId and uid of attestations to revoke
|
|
243
|
+
* @param callback - Optional callback function for status updates
|
|
244
|
+
* @returns Promise with transaction and UIDs of revoked attestations
|
|
245
|
+
*/
|
|
246
|
+
async revokeMultipleAttestations(
|
|
247
|
+
signer: SignerOrProvider,
|
|
248
|
+
attestationsToRevoke: MultiRevokeArgs[],
|
|
249
|
+
callback?: Function
|
|
250
|
+
): Promise<AttestationWithTx> {
|
|
251
|
+
if (attestationsToRevoke.length === 0) {
|
|
252
|
+
throw new AttestationError(
|
|
253
|
+
"ATTEST_ERROR",
|
|
254
|
+
"No attestations specified for revocation"
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Group the attestations by schema ID
|
|
259
|
+
const groupedAttestations = attestationsToRevoke.reduce(
|
|
260
|
+
(acc, { schemaId, uid }) => {
|
|
261
|
+
if (!acc[schemaId]) {
|
|
262
|
+
acc[schemaId] = [];
|
|
263
|
+
}
|
|
264
|
+
acc[schemaId].push(uid);
|
|
265
|
+
return acc;
|
|
266
|
+
},
|
|
267
|
+
{} as Record<Hex, Hex[]>
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
// Convert to the format expected by GapContract.multiRevoke
|
|
271
|
+
const revocationPayload = Object.entries(groupedAttestations).map(
|
|
272
|
+
([schemaId, uids]) => ({
|
|
273
|
+
schema: schemaId,
|
|
274
|
+
data: uids.map((uid) => ({
|
|
275
|
+
uid,
|
|
276
|
+
value: 0n, // EAS contract requires a value field as BigInt
|
|
277
|
+
})),
|
|
278
|
+
})
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
// Use GapContract.multiRevoke directly with the correct payload format
|
|
282
|
+
const result = await GapContract.multiRevoke(signer, revocationPayload);
|
|
283
|
+
|
|
284
|
+
if (callback) {
|
|
285
|
+
callback("confirmed");
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Marks a milestone as completed. If the milestone is already completed,
|
|
293
|
+
* it will throw an error.
|
|
294
|
+
* @param signer
|
|
295
|
+
* @param reason
|
|
296
|
+
*/
|
|
297
|
+
async complete(
|
|
298
|
+
signer: SignerOrProvider,
|
|
299
|
+
data?: IMilestoneCompleted,
|
|
300
|
+
callback?: Function
|
|
301
|
+
): Promise<AttestationWithTx> {
|
|
302
|
+
const schema = this.schema.gap.findSchema("MilestoneCompleted");
|
|
303
|
+
|
|
304
|
+
if (this.schema.isJsonSchema()) {
|
|
305
|
+
schema.setValue(
|
|
306
|
+
"json",
|
|
307
|
+
JSON.stringify({
|
|
308
|
+
type: "completed",
|
|
309
|
+
...data,
|
|
310
|
+
})
|
|
311
|
+
);
|
|
312
|
+
} else {
|
|
313
|
+
schema.setValue("type", "completed");
|
|
314
|
+
schema.setValue("reason", data?.reason || "");
|
|
315
|
+
schema.setValue("proofOfWork", data?.proofOfWork || "");
|
|
316
|
+
}
|
|
317
|
+
const { tx, uids } = await this.attestStatus(signer, schema, callback);
|
|
318
|
+
this.completed = new MilestoneCompleted({
|
|
319
|
+
data: {
|
|
320
|
+
type: "completed",
|
|
321
|
+
...data,
|
|
322
|
+
},
|
|
323
|
+
refUID: this.uid,
|
|
324
|
+
schema,
|
|
325
|
+
recipient: this.recipient,
|
|
326
|
+
});
|
|
327
|
+
return { tx, uids };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Marks a milestone as completed across multiple grants. If the milestone is already completed,
|
|
332
|
+
* it will throw an error.
|
|
333
|
+
* @param signer - The signer to use for attestation
|
|
334
|
+
* @param grantIndices - Array of grant indices to attest this milestone to, or array of milestone UIDs
|
|
335
|
+
* @param data - Optional completion data
|
|
336
|
+
* @param callback - Optional callback function for status updates
|
|
337
|
+
* @returns Promise with transaction and UIDs
|
|
338
|
+
*/
|
|
339
|
+
async completeForMultipleGrants(
|
|
340
|
+
signer: SignerOrProvider,
|
|
341
|
+
grantIndicesOrMilestoneUIDs: number[] | Hex[] = [0],
|
|
342
|
+
data?: IMilestoneCompleted,
|
|
343
|
+
callback?: Function
|
|
344
|
+
): Promise<AttestationWithTx> {
|
|
345
|
+
// Check if we're dealing with UIDs instead of indices
|
|
346
|
+
const isUids =
|
|
347
|
+
grantIndicesOrMilestoneUIDs.length > 0 &&
|
|
348
|
+
typeof grantIndicesOrMilestoneUIDs[0] === "string";
|
|
349
|
+
|
|
350
|
+
let milestoneUIDs: Hex[] = [];
|
|
351
|
+
|
|
352
|
+
if (isUids) {
|
|
353
|
+
// We already have milestone UIDs
|
|
354
|
+
milestoneUIDs = grantIndicesOrMilestoneUIDs as Hex[];
|
|
355
|
+
} else {
|
|
356
|
+
// First attest the milestone to multiple grants if not already attested
|
|
357
|
+
const attestResult = await this.attestToMultipleGrants(
|
|
358
|
+
signer,
|
|
359
|
+
grantIndicesOrMilestoneUIDs as number[],
|
|
360
|
+
callback
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
milestoneUIDs = attestResult.uids;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Now complete the milestone for each attested milestone
|
|
367
|
+
const schema = this.schema.gap.findSchema("MilestoneCompleted");
|
|
368
|
+
|
|
369
|
+
if (this.schema.isJsonSchema()) {
|
|
370
|
+
schema.setValue(
|
|
371
|
+
"json",
|
|
372
|
+
JSON.stringify({
|
|
373
|
+
type: "completed",
|
|
374
|
+
...data,
|
|
375
|
+
})
|
|
376
|
+
);
|
|
377
|
+
} else {
|
|
378
|
+
schema.setValue("type", "completed");
|
|
379
|
+
schema.setValue("reason", data?.reason || "");
|
|
380
|
+
schema.setValue("proofOfWork", data?.proofOfWork || "");
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Create completion attestations for each milestone
|
|
384
|
+
const completionPayloads: MultiAttestPayload = [];
|
|
385
|
+
|
|
386
|
+
for (let i = 0; i < milestoneUIDs.length; i++) {
|
|
387
|
+
const milestoneUID = milestoneUIDs[i];
|
|
388
|
+
|
|
389
|
+
// Only set this.uid if we're dealing with indices and need to update the current milestone
|
|
390
|
+
if (!isUids) {
|
|
391
|
+
this.uid = milestoneUID; // Set the current UID to the milestone being completed
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const completed = new MilestoneCompleted({
|
|
395
|
+
data: {
|
|
396
|
+
type: "completed",
|
|
397
|
+
...data,
|
|
398
|
+
},
|
|
399
|
+
refUID: milestoneUID,
|
|
400
|
+
schema,
|
|
401
|
+
recipient: this.recipient,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// Add completed status to the payload
|
|
405
|
+
completionPayloads.push([completed, await completed.payloadFor(i)]);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Attest all completions at once
|
|
409
|
+
const completionResult = await GapContract.multiAttest(
|
|
410
|
+
signer,
|
|
411
|
+
completionPayloads.map((p) => p[1]),
|
|
412
|
+
callback
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
// Save the first completion to this milestone instance
|
|
416
|
+
if (completionResult.uids.length > 0 && !isUids) {
|
|
417
|
+
this.completed = new MilestoneCompleted({
|
|
418
|
+
data: {
|
|
419
|
+
type: "completed",
|
|
420
|
+
...data,
|
|
421
|
+
},
|
|
422
|
+
refUID: milestoneUIDs[0],
|
|
423
|
+
uid: completionResult.uids[0],
|
|
424
|
+
schema,
|
|
425
|
+
recipient: this.recipient,
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return isUids
|
|
430
|
+
? completionResult // If we're using UIDs directly, just return completion result
|
|
431
|
+
: {
|
|
432
|
+
tx: [
|
|
433
|
+
...(milestoneUIDs.length ? [{ hash: "" } as Transaction] : []),
|
|
434
|
+
...completionResult.tx,
|
|
435
|
+
],
|
|
436
|
+
uids: [...milestoneUIDs, ...completionResult.uids],
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Revokes the completed status of the milestone. If the milestone is not completed,
|
|
442
|
+
* it will throw an error.
|
|
443
|
+
* @param signer
|
|
444
|
+
*/
|
|
445
|
+
async revokeCompletion(signer: SignerOrProvider, callback?: Function) {
|
|
446
|
+
if (!this.completed)
|
|
447
|
+
throw new AttestationError("ATTEST_ERROR", "Milestone is not completed");
|
|
448
|
+
|
|
449
|
+
const { tx, uids } = await this.completed.schema.multiRevoke(
|
|
450
|
+
signer,
|
|
451
|
+
[
|
|
452
|
+
{
|
|
453
|
+
schemaId: this.completed.schema.uid,
|
|
454
|
+
uid: this.completed.uid,
|
|
455
|
+
},
|
|
456
|
+
],
|
|
457
|
+
callback
|
|
458
|
+
);
|
|
459
|
+
return { tx, uids };
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Creates the payload for a multi-attestation.
|
|
464
|
+
*
|
|
465
|
+
* > if Current payload is set, it'll be used as the base payload
|
|
466
|
+
* and the project should refer to an index of the current payload,
|
|
467
|
+
* usually the community position.
|
|
468
|
+
*
|
|
469
|
+
* @param payload
|
|
470
|
+
* @param grantIdx
|
|
471
|
+
*/
|
|
472
|
+
async multiAttestPayload(
|
|
473
|
+
currentPayload: MultiAttestPayload = [],
|
|
474
|
+
grantIdx = 0
|
|
475
|
+
) {
|
|
476
|
+
this.assertPayload();
|
|
477
|
+
const payload = [...currentPayload];
|
|
478
|
+
const milestoneIdx =
|
|
479
|
+
payload.push([this, await this.payloadFor(grantIdx)]) - 1;
|
|
480
|
+
if (this.completed) {
|
|
481
|
+
payload.push([
|
|
482
|
+
this.completed,
|
|
483
|
+
await this.completed.payloadFor(milestoneIdx),
|
|
484
|
+
]);
|
|
485
|
+
}
|
|
486
|
+
if (this.verified.length > 0) {
|
|
487
|
+
await Promise.all(
|
|
488
|
+
this.verified.map(async (m) => {
|
|
489
|
+
const payloadForMilestone = await m.payloadFor(milestoneIdx);
|
|
490
|
+
if (Array.isArray(payloadForMilestone)) {
|
|
491
|
+
payloadForMilestone.forEach((item) => payload.push(item));
|
|
492
|
+
}
|
|
493
|
+
})
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
return payload.slice(currentPayload.length, payload.length);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Creates the payload for a multi-attestation across multiple grants.
|
|
501
|
+
*
|
|
502
|
+
* This method allows for the same milestone to be attested to multiple grants
|
|
503
|
+
* in a single transaction.
|
|
504
|
+
*
|
|
505
|
+
* @param currentPayload - Current payload to append to
|
|
506
|
+
* @param grantIndices - Array of grant indices to attest this milestone to
|
|
507
|
+
* @returns The multi-attest payload with all grant attestations
|
|
508
|
+
*/
|
|
509
|
+
async multiGrantAttestPayload(
|
|
510
|
+
currentPayload: MultiAttestPayload = [],
|
|
511
|
+
grantIndices: number[] = [0]
|
|
512
|
+
) {
|
|
513
|
+
this.assertPayload();
|
|
514
|
+
const payload = [...currentPayload];
|
|
515
|
+
const milestoneIndices: number[] = [];
|
|
516
|
+
|
|
517
|
+
// Create milestone attestation for each grant
|
|
518
|
+
for (const grantIdx of grantIndices) {
|
|
519
|
+
const milestoneIdx =
|
|
520
|
+
payload.push([this, await this.payloadFor(grantIdx)]) - 1;
|
|
521
|
+
milestoneIndices.push(milestoneIdx);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Add completed status if exists for each milestone
|
|
525
|
+
if (this.completed) {
|
|
526
|
+
for (const milestoneIdx of milestoneIndices) {
|
|
527
|
+
payload.push([
|
|
528
|
+
this.completed,
|
|
529
|
+
await this.completed.payloadFor(milestoneIdx),
|
|
530
|
+
]);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Add verifications if exist for each milestone
|
|
535
|
+
if (this.verified.length > 0) {
|
|
536
|
+
for (const milestoneIdx of milestoneIndices) {
|
|
537
|
+
await Promise.all(
|
|
538
|
+
this.verified.map(async (m) => {
|
|
539
|
+
const payloadForMilestone = await m.payloadFor(milestoneIdx);
|
|
540
|
+
if (Array.isArray(payloadForMilestone)) {
|
|
541
|
+
payloadForMilestone.forEach((item) => payload.push(item));
|
|
542
|
+
}
|
|
543
|
+
})
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return payload.slice(currentPayload.length, payload.length);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Attests this milestone to multiple grants in a single transaction.
|
|
553
|
+
*
|
|
554
|
+
* @param signer - The signer to use for attestation
|
|
555
|
+
* @param grantIndices - Array of grant indices to attest this milestone to, or array of grant UIDs
|
|
556
|
+
* @param callback - Optional callback function for status updates
|
|
557
|
+
* @returns Promise with transaction and UIDs
|
|
558
|
+
*/
|
|
559
|
+
async attestToMultipleGrants(
|
|
560
|
+
signer: SignerOrProvider,
|
|
561
|
+
grantIndices: number[] | Hex[] = [0],
|
|
562
|
+
callback?: Function
|
|
563
|
+
): Promise<AttestationWithTx> {
|
|
564
|
+
this.assertPayload();
|
|
565
|
+
|
|
566
|
+
// Check if we're dealing with Hex UIDs instead of indices
|
|
567
|
+
const isUids =
|
|
568
|
+
grantIndices.length > 0 && typeof grantIndices[0] === "string";
|
|
569
|
+
|
|
570
|
+
if (isUids) {
|
|
571
|
+
// Direct approach - create individual milestone instances for each grant UID
|
|
572
|
+
const grantUIDs = grantIndices as Hex[];
|
|
573
|
+
const allPayloads: any[] = [];
|
|
574
|
+
|
|
575
|
+
for (const grantUID of grantUIDs) {
|
|
576
|
+
// Create a new milestone for each grant with direct reference
|
|
577
|
+
const grantMilestone = new Milestone({
|
|
578
|
+
schema: this.schema,
|
|
579
|
+
recipient: this.recipient,
|
|
580
|
+
data: this.data,
|
|
581
|
+
refUID: grantUID,
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
// Generate payload for this grant
|
|
585
|
+
const payload = await grantMilestone.multiAttestPayload();
|
|
586
|
+
// Add each item from payload to allPayloads
|
|
587
|
+
payload.forEach((item) => allPayloads.push(item));
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Attest all milestones in a single transaction
|
|
591
|
+
const result = await GapContract.multiAttest(
|
|
592
|
+
signer,
|
|
593
|
+
allPayloads.map((p) => p[1]),
|
|
594
|
+
callback
|
|
595
|
+
);
|
|
596
|
+
|
|
597
|
+
return result;
|
|
598
|
+
} else {
|
|
599
|
+
// Original implementation using grantIndices
|
|
600
|
+
const payload = await this.multiGrantAttestPayload(
|
|
601
|
+
[],
|
|
602
|
+
grantIndices as number[]
|
|
603
|
+
);
|
|
604
|
+
|
|
605
|
+
const { uids, tx } = await GapContract.multiAttest(
|
|
606
|
+
signer,
|
|
607
|
+
payload.map((p) => p[1]),
|
|
608
|
+
callback
|
|
609
|
+
);
|
|
610
|
+
|
|
611
|
+
if (Array.isArray(uids)) {
|
|
612
|
+
uids.forEach((uid, index) => {
|
|
613
|
+
payload[index][0].uid = uid;
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return { tx, uids };
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* @inheritdoc
|
|
623
|
+
*/
|
|
624
|
+
async attest(
|
|
625
|
+
signer: SignerOrProvider,
|
|
626
|
+
callback?: Function
|
|
627
|
+
): Promise<AttestationWithTx> {
|
|
628
|
+
this.assertPayload();
|
|
629
|
+
const payload = await this.multiAttestPayload();
|
|
630
|
+
|
|
631
|
+
const { uids, tx } = await GapContract.multiAttest(
|
|
632
|
+
signer,
|
|
633
|
+
payload.map((p) => p[1]),
|
|
634
|
+
callback
|
|
635
|
+
);
|
|
636
|
+
if (Array.isArray(uids)) {
|
|
637
|
+
uids.forEach((uid, index) => {
|
|
638
|
+
payload[index][0].uid = uid;
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
console.log(uids);
|
|
642
|
+
|
|
643
|
+
return { tx, uids };
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Attest the status of the milestone as approved, rejected or completed.
|
|
648
|
+
*/
|
|
649
|
+
private async attestStatus(
|
|
650
|
+
signer: SignerOrProvider,
|
|
651
|
+
schema: GapSchema,
|
|
652
|
+
callback?: Function
|
|
653
|
+
): Promise<AttestationWithTx> {
|
|
654
|
+
const eas = this.schema.gap.eas.connect(signer);
|
|
655
|
+
try {
|
|
656
|
+
if (callback) callback("preparing");
|
|
657
|
+
const tx = await eas.attest({
|
|
658
|
+
schema: schema.uid,
|
|
659
|
+
data: {
|
|
660
|
+
recipient: this.recipient,
|
|
661
|
+
data: schema.encode(),
|
|
662
|
+
refUID: this.uid,
|
|
663
|
+
expirationTime: 0n,
|
|
664
|
+
revocable: schema.revocable,
|
|
665
|
+
},
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
if (callback) callback("pending");
|
|
669
|
+
const uid = await tx.wait();
|
|
670
|
+
if (callback) callback("confirmed");
|
|
671
|
+
console.log(uid);
|
|
672
|
+
|
|
673
|
+
return {
|
|
674
|
+
tx: [
|
|
675
|
+
{
|
|
676
|
+
hash: tx.tx.hash as Hex,
|
|
677
|
+
} as Transaction,
|
|
678
|
+
],
|
|
679
|
+
uids: [uid as `0x${string}`],
|
|
680
|
+
};
|
|
681
|
+
} catch (error: any) {
|
|
682
|
+
console.error(error);
|
|
683
|
+
throw new AttestationError("ATTEST_ERROR", error.message, error);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
static from(
|
|
688
|
+
attestations: IMilestoneResponse[],
|
|
689
|
+
network: TNetwork
|
|
690
|
+
): Milestone[] {
|
|
691
|
+
return attestations.map((attestation) => {
|
|
692
|
+
const milestone = new Milestone({
|
|
693
|
+
...attestation,
|
|
694
|
+
data: {
|
|
695
|
+
...attestation.data,
|
|
696
|
+
},
|
|
697
|
+
schema: new AllGapSchemas().findSchema(
|
|
698
|
+
"Milestone",
|
|
699
|
+
chainIdToNetwork[attestation.chainID] as TNetwork
|
|
700
|
+
),
|
|
701
|
+
chainID: attestation.chainID,
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
if (attestation.completed) {
|
|
705
|
+
milestone.completed = new MilestoneCompleted({
|
|
706
|
+
...attestation.completed,
|
|
707
|
+
data: {
|
|
708
|
+
...attestation.completed.data,
|
|
709
|
+
},
|
|
710
|
+
schema: new AllGapSchemas().findSchema(
|
|
711
|
+
"MilestoneCompleted",
|
|
712
|
+
chainIdToNetwork[attestation.chainID] as TNetwork
|
|
713
|
+
),
|
|
714
|
+
chainID: attestation.chainID,
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (attestation.approved) {
|
|
719
|
+
milestone.approved = new MilestoneCompleted({
|
|
720
|
+
...attestation.approved,
|
|
721
|
+
data: {
|
|
722
|
+
...attestation.completed.data,
|
|
723
|
+
},
|
|
724
|
+
schema: new AllGapSchemas().findSchema(
|
|
725
|
+
"MilestoneCompleted",
|
|
726
|
+
chainIdToNetwork[attestation.chainID] as TNetwork
|
|
727
|
+
),
|
|
728
|
+
chainID: attestation.chainID,
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
if (attestation.rejected) {
|
|
733
|
+
milestone.rejected = new MilestoneCompleted({
|
|
734
|
+
...attestation.rejected,
|
|
735
|
+
data: {
|
|
736
|
+
...attestation.completed.data,
|
|
737
|
+
},
|
|
738
|
+
schema: new AllGapSchemas().findSchema(
|
|
739
|
+
"MilestoneCompleted",
|
|
740
|
+
chainIdToNetwork[attestation.chainID] as TNetwork
|
|
741
|
+
),
|
|
742
|
+
chainID: attestation.chainID,
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
if (attestation.verified?.length > 0) {
|
|
747
|
+
milestone.verified = attestation.verified.map(
|
|
748
|
+
(m) =>
|
|
749
|
+
new MilestoneCompleted({
|
|
750
|
+
...m,
|
|
751
|
+
data: {
|
|
752
|
+
...m.data,
|
|
753
|
+
},
|
|
754
|
+
schema: new AllGapSchemas().findSchema(
|
|
755
|
+
"MilestoneCompleted",
|
|
756
|
+
chainIdToNetwork[attestation.chainID] as TNetwork
|
|
757
|
+
),
|
|
758
|
+
chainID: attestation.chainID,
|
|
759
|
+
})
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
return milestone;
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Verify this milestone. If the milestone is not completed or already verified,
|
|
769
|
+
* it will throw an error.
|
|
770
|
+
* @param signer
|
|
771
|
+
* @param reason
|
|
772
|
+
*/
|
|
773
|
+
async verify(
|
|
774
|
+
signer: SignerOrProvider,
|
|
775
|
+
data?: IMilestoneCompleted,
|
|
776
|
+
callback?: Function
|
|
777
|
+
): Promise<AttestationWithTx> {
|
|
778
|
+
console.log("Verifying");
|
|
779
|
+
if (!this.completed)
|
|
780
|
+
throw new AttestationError("ATTEST_ERROR", "Milestone is not completed");
|
|
781
|
+
|
|
782
|
+
const schema = this.schema.gap.findSchema("MilestoneCompleted");
|
|
783
|
+
|
|
784
|
+
if (this.schema.isJsonSchema()) {
|
|
785
|
+
schema.setValue(
|
|
786
|
+
"json",
|
|
787
|
+
JSON.stringify({
|
|
788
|
+
type: "verified",
|
|
789
|
+
...data,
|
|
790
|
+
})
|
|
791
|
+
);
|
|
792
|
+
} else {
|
|
793
|
+
schema.setValue("type", "verified");
|
|
794
|
+
schema.setValue("reason", data?.reason || "");
|
|
795
|
+
schema.setValue("proofOfWork", data?.proofOfWork || "");
|
|
796
|
+
}
|
|
797
|
+
console.log("Before attestStatus");
|
|
798
|
+
const { tx, uids } = await this.attestStatus(signer, schema, callback);
|
|
799
|
+
console.log("After attestStatus");
|
|
800
|
+
|
|
801
|
+
this.verified.push(
|
|
802
|
+
new MilestoneCompleted({
|
|
803
|
+
data: {
|
|
804
|
+
type: "verified",
|
|
805
|
+
...data,
|
|
806
|
+
},
|
|
807
|
+
refUID: this.uid,
|
|
808
|
+
schema: schema,
|
|
809
|
+
recipient: this.recipient,
|
|
810
|
+
})
|
|
811
|
+
);
|
|
812
|
+
return { tx, uids };
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Verifies this milestone across multiple grants. If the milestones are not completed,
|
|
817
|
+
* it will throw an error.
|
|
818
|
+
* @param signer - The signer to use for attestation
|
|
819
|
+
* @param milestoneUIDs - Array of milestone UIDs to verify
|
|
820
|
+
* @param data - Optional verification data
|
|
821
|
+
* @param callback - Optional callback function for status updates
|
|
822
|
+
* @returns Promise with transaction and UIDs
|
|
823
|
+
*/
|
|
824
|
+
async verifyMultipleGrants(
|
|
825
|
+
signer: SignerOrProvider,
|
|
826
|
+
milestoneUIDs: Hex[],
|
|
827
|
+
data?: IMilestoneCompleted,
|
|
828
|
+
callback?: Function
|
|
829
|
+
): Promise<AttestationWithTx> {
|
|
830
|
+
// Validate that all milestones are completed
|
|
831
|
+
if (!this.completed)
|
|
832
|
+
throw new AttestationError("ATTEST_ERROR", "Milestone is not completed");
|
|
833
|
+
|
|
834
|
+
const schema = this.schema.gap.findSchema("MilestoneCompleted");
|
|
835
|
+
|
|
836
|
+
if (this.schema.isJsonSchema()) {
|
|
837
|
+
schema.setValue(
|
|
838
|
+
"json",
|
|
839
|
+
JSON.stringify({
|
|
840
|
+
type: "verified",
|
|
841
|
+
...data,
|
|
842
|
+
})
|
|
843
|
+
);
|
|
844
|
+
} else {
|
|
845
|
+
schema.setValue("type", "verified");
|
|
846
|
+
schema.setValue("reason", data?.reason || "");
|
|
847
|
+
schema.setValue("proofOfWork", data?.proofOfWork || "");
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Create verification attestations for each milestone
|
|
851
|
+
const verificationPayloads: MultiAttestPayload = [];
|
|
852
|
+
|
|
853
|
+
for (const milestoneUID of milestoneUIDs) {
|
|
854
|
+
const verified = new MilestoneCompleted({
|
|
855
|
+
data: {
|
|
856
|
+
type: "verified",
|
|
857
|
+
...data,
|
|
858
|
+
},
|
|
859
|
+
refUID: milestoneUID,
|
|
860
|
+
schema,
|
|
861
|
+
recipient: this.recipient,
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
// Add verification to the payload
|
|
865
|
+
verificationPayloads.push([
|
|
866
|
+
verified,
|
|
867
|
+
await verified.payloadFor(0), // Index doesn't matter for verification
|
|
868
|
+
]);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// Attest all verifications at once
|
|
872
|
+
const result = await GapContract.multiAttest(
|
|
873
|
+
signer,
|
|
874
|
+
verificationPayloads.map((p) => p[1]),
|
|
875
|
+
callback
|
|
876
|
+
);
|
|
877
|
+
|
|
878
|
+
// Save the verifications to this milestone instance
|
|
879
|
+
if (result.uids.length > 0) {
|
|
880
|
+
for (let i = 0; i < result.uids.length; i++) {
|
|
881
|
+
this.verified.push(
|
|
882
|
+
new MilestoneCompleted({
|
|
883
|
+
data: {
|
|
884
|
+
type: "verified",
|
|
885
|
+
...data,
|
|
886
|
+
},
|
|
887
|
+
refUID: milestoneUIDs[i],
|
|
888
|
+
uid: result.uids[i],
|
|
889
|
+
schema,
|
|
890
|
+
recipient: this.recipient,
|
|
891
|
+
})
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
return result;
|
|
897
|
+
}
|
|
898
|
+
}
|