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