@grapenpm/gpass-sdk 0.1.0
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/README.md +251 -0
- package/dist/index.d.mts +1041 -0
- package/dist/index.d.ts +1041 -0
- package/dist/index.js +3609 -0
- package/dist/index.mjs +3592 -0
- package/package.json +50 -0
- package/src/bn-js.d.ts +18 -0
- package/src/client.ts +349 -0
- package/src/idl.ts +531 -0
- package/src/index.ts +44 -0
- package/src/pda.ts +125 -0
- package/src/types/index.ts +294 -0
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@grapenpm/gpass-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "SDK for the Grape Gating Protocol (GPASS) - composable access control for Solana DAOs",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
14
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
15
|
+
"test": "jest",
|
|
16
|
+
"lint": "eslint src --ext .ts",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"solana",
|
|
21
|
+
"anchor",
|
|
22
|
+
"grape",
|
|
23
|
+
"gating",
|
|
24
|
+
"dao",
|
|
25
|
+
"web3",
|
|
26
|
+
"reputation",
|
|
27
|
+
"verification"
|
|
28
|
+
],
|
|
29
|
+
"author": "Grape Protocol",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@coral-xyz/anchor": "^0.29.0",
|
|
33
|
+
"@solana/web3.js": "^1.87.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@coral-xyz/anchor": "^0.29.0",
|
|
37
|
+
"@solana/web3.js": "^1.87.0",
|
|
38
|
+
"@types/jest": "^29.5.0",
|
|
39
|
+
"@types/node": "^20.0.0",
|
|
40
|
+
"tsup": "^8.0.0",
|
|
41
|
+
"typescript": "^5.0.0"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/Grape-Labs/grape-gating-protocol"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/bn-js.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
declare module "bn.js" {
|
|
2
|
+
class BN {
|
|
3
|
+
constructor(
|
|
4
|
+
value?:
|
|
5
|
+
| number
|
|
6
|
+
| string
|
|
7
|
+
| number[]
|
|
8
|
+
| Uint8Array
|
|
9
|
+
| Buffer
|
|
10
|
+
| BN,
|
|
11
|
+
base?: number | "hex",
|
|
12
|
+
endian?: "le" | "be"
|
|
13
|
+
);
|
|
14
|
+
toNumber(): number;
|
|
15
|
+
toString(base?: number | "hex", length?: number): string;
|
|
16
|
+
}
|
|
17
|
+
export default BN;
|
|
18
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AnchorProvider,
|
|
3
|
+
Program,
|
|
4
|
+
BN,
|
|
5
|
+
} from "@coral-xyz/anchor";
|
|
6
|
+
import {
|
|
7
|
+
PublicKey,
|
|
8
|
+
SystemProgram,
|
|
9
|
+
TransactionInstruction,
|
|
10
|
+
Transaction,
|
|
11
|
+
SendTransactionError,
|
|
12
|
+
} from "@solana/web3.js";
|
|
13
|
+
import { IDL, GrapeGatingProtocol } from "./idl";
|
|
14
|
+
import {
|
|
15
|
+
GPASS_PROGRAM_ID,
|
|
16
|
+
Gate,
|
|
17
|
+
GateCheckRecord,
|
|
18
|
+
GateCriteria,
|
|
19
|
+
GateType,
|
|
20
|
+
GateTypeFactory,
|
|
21
|
+
InitializeGateParams,
|
|
22
|
+
CheckGateParams,
|
|
23
|
+
UpdateGateCriteriaParams,
|
|
24
|
+
SetGateActiveParams,
|
|
25
|
+
CloseGateParams,
|
|
26
|
+
} from "./types";
|
|
27
|
+
import {
|
|
28
|
+
findGatePda,
|
|
29
|
+
findCheckRecordPda,
|
|
30
|
+
} from "./pda";
|
|
31
|
+
|
|
32
|
+
export class GpassClient {
|
|
33
|
+
public readonly program: Program<GrapeGatingProtocol>;
|
|
34
|
+
public readonly provider: AnchorProvider;
|
|
35
|
+
|
|
36
|
+
constructor(provider: AnchorProvider, programId: PublicKey = GPASS_PROGRAM_ID) {
|
|
37
|
+
this.provider = provider;
|
|
38
|
+
this.program = new Program<GrapeGatingProtocol>(IDL, programId, provider);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ─────────────────────────────────────────────────────
|
|
42
|
+
// INITIALIZE GATE
|
|
43
|
+
// ─────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create a new gate with the given criteria.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const { tx, gate } = await client.initializeGate({
|
|
50
|
+
* gateId: Keypair.generate().publicKey,
|
|
51
|
+
* criteria: GateCriteriaFactory.combined({
|
|
52
|
+
* vineConfig,
|
|
53
|
+
* minPoints: 500,
|
|
54
|
+
* season: 1,
|
|
55
|
+
* grapeSpace,
|
|
56
|
+
* platforms: [VerificationPlatform.Discord],
|
|
57
|
+
* requireWalletLink: true,
|
|
58
|
+
* }),
|
|
59
|
+
* gateType: GateTypeFactory.reusable(),
|
|
60
|
+
* });
|
|
61
|
+
*/
|
|
62
|
+
async initializeGate(params: InitializeGateParams): Promise<{
|
|
63
|
+
tx: string;
|
|
64
|
+
gate: PublicKey;
|
|
65
|
+
}> {
|
|
66
|
+
const authority = params.authority ?? this.provider.wallet.publicKey;
|
|
67
|
+
const [gatePda] = await findGatePda(params.gateId);
|
|
68
|
+
|
|
69
|
+
const tx = await this.program.methods
|
|
70
|
+
.initializeGate(params.gateId, params.criteria as any, params.gateType as any)
|
|
71
|
+
.accounts({
|
|
72
|
+
gate: gatePda,
|
|
73
|
+
authority,
|
|
74
|
+
payer: this.provider.wallet.publicKey,
|
|
75
|
+
systemProgram: SystemProgram.programId,
|
|
76
|
+
})
|
|
77
|
+
.rpc();
|
|
78
|
+
|
|
79
|
+
return { tx, gate: gatePda };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ─────────────────────────────────────────────────────
|
|
83
|
+
// CHECK GATE
|
|
84
|
+
// ─────────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check whether a user passes a gate's criteria.
|
|
88
|
+
* Throws GateCheckFailed (6002) if the user does not pass.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* await client.checkGate({
|
|
92
|
+
* gateId,
|
|
93
|
+
* user: walletPublicKey,
|
|
94
|
+
* reputationAccount: vineRepPda,
|
|
95
|
+
* identityAccount: grapeIdentityPda,
|
|
96
|
+
* storeRecord: true,
|
|
97
|
+
* });
|
|
98
|
+
*/
|
|
99
|
+
async checkGate(params: CheckGateParams): Promise<string> {
|
|
100
|
+
const [gatePda] = await findGatePda(params.gateId);
|
|
101
|
+
const [checkRecordPda] = params.storeRecord
|
|
102
|
+
? await findCheckRecordPda(gatePda, params.user)
|
|
103
|
+
: [null];
|
|
104
|
+
|
|
105
|
+
const tx = await this.program.methods
|
|
106
|
+
.checkGate(params.gateId)
|
|
107
|
+
.accounts({
|
|
108
|
+
gate: gatePda,
|
|
109
|
+
user: params.user,
|
|
110
|
+
reputationAccount: params.reputationAccount ?? null,
|
|
111
|
+
identityAccount: params.identityAccount ?? null,
|
|
112
|
+
linkAccount: params.linkAccount ?? null,
|
|
113
|
+
tokenAccount: params.tokenAccount ?? null,
|
|
114
|
+
checkRecord: checkRecordPda ?? null,
|
|
115
|
+
payer: this.provider.wallet.publicKey,
|
|
116
|
+
systemProgram: SystemProgram.programId,
|
|
117
|
+
})
|
|
118
|
+
.rpc();
|
|
119
|
+
|
|
120
|
+
return tx;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Simulate a gate check without submitting a transaction.
|
|
125
|
+
* Returns true if the user would pass, false otherwise.
|
|
126
|
+
* Does NOT throw — use this for UI gating.
|
|
127
|
+
*/
|
|
128
|
+
async simulateCheckGate(params: CheckGateParams): Promise<boolean> {
|
|
129
|
+
try {
|
|
130
|
+
const [gatePda] = await findGatePda(params.gateId);
|
|
131
|
+
const [checkRecordPda] = params.storeRecord
|
|
132
|
+
? await findCheckRecordPda(gatePda, params.user)
|
|
133
|
+
: [null];
|
|
134
|
+
|
|
135
|
+
await this.program.methods
|
|
136
|
+
.checkGate(params.gateId)
|
|
137
|
+
.accounts({
|
|
138
|
+
gate: gatePda,
|
|
139
|
+
user: params.user,
|
|
140
|
+
reputationAccount: params.reputationAccount ?? null,
|
|
141
|
+
identityAccount: params.identityAccount ?? null,
|
|
142
|
+
linkAccount: params.linkAccount ?? null,
|
|
143
|
+
tokenAccount: params.tokenAccount ?? null,
|
|
144
|
+
checkRecord: checkRecordPda ?? null,
|
|
145
|
+
payer: this.provider.wallet.publicKey,
|
|
146
|
+
systemProgram: SystemProgram.programId,
|
|
147
|
+
})
|
|
148
|
+
.simulate();
|
|
149
|
+
|
|
150
|
+
return true;
|
|
151
|
+
} catch {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ─────────────────────────────────────────────────────
|
|
157
|
+
// UPDATE GATE
|
|
158
|
+
// ─────────────────────────────────────────────────────
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Update the criteria for an existing gate.
|
|
162
|
+
*/
|
|
163
|
+
async updateGateCriteria(params: UpdateGateCriteriaParams): Promise<string> {
|
|
164
|
+
const [gatePda] = await findGatePda(params.gateId);
|
|
165
|
+
|
|
166
|
+
return this.program.methods
|
|
167
|
+
.updateGateCriteria(params.gateId, params.newCriteria as any)
|
|
168
|
+
.accounts({
|
|
169
|
+
gate: gatePda,
|
|
170
|
+
authority: this.provider.wallet.publicKey,
|
|
171
|
+
})
|
|
172
|
+
.rpc();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Enable or disable a gate.
|
|
177
|
+
*/
|
|
178
|
+
async setGateActive(params: SetGateActiveParams): Promise<string> {
|
|
179
|
+
const [gatePda] = await findGatePda(params.gateId);
|
|
180
|
+
|
|
181
|
+
return this.program.methods
|
|
182
|
+
.setGateActive(params.gateId, params.isActive)
|
|
183
|
+
.accounts({
|
|
184
|
+
gate: gatePda,
|
|
185
|
+
authority: this.provider.wallet.publicKey,
|
|
186
|
+
})
|
|
187
|
+
.rpc();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Transfer gate authority to a new public key.
|
|
192
|
+
*/
|
|
193
|
+
async setGateAuthority(params: {
|
|
194
|
+
gateId: PublicKey;
|
|
195
|
+
newAuthority: PublicKey;
|
|
196
|
+
}): Promise<string> {
|
|
197
|
+
const [gatePda] = await findGatePda(params.gateId);
|
|
198
|
+
|
|
199
|
+
return this.program.methods
|
|
200
|
+
.setGateAuthority(params.gateId, params.newAuthority)
|
|
201
|
+
.accounts({
|
|
202
|
+
gate: gatePda,
|
|
203
|
+
authority: this.provider.wallet.publicKey,
|
|
204
|
+
})
|
|
205
|
+
.rpc();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ─────────────────────────────────────────────────────
|
|
209
|
+
// CLOSE
|
|
210
|
+
// ─────────────────────────────────────────────────────
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Close a gate and reclaim rent.
|
|
214
|
+
*/
|
|
215
|
+
async closeGate(params: CloseGateParams): Promise<string> {
|
|
216
|
+
const [gatePda] = await findGatePda(params.gateId);
|
|
217
|
+
const recipient = params.recipient ?? this.provider.wallet.publicKey;
|
|
218
|
+
|
|
219
|
+
return this.program.methods
|
|
220
|
+
.closeGate(params.gateId)
|
|
221
|
+
.accounts({
|
|
222
|
+
gate: gatePda,
|
|
223
|
+
authority: this.provider.wallet.publicKey,
|
|
224
|
+
recipient,
|
|
225
|
+
})
|
|
226
|
+
.rpc();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Close a check record and reclaim rent.
|
|
231
|
+
*/
|
|
232
|
+
async closeCheckRecord(params: {
|
|
233
|
+
gateId: PublicKey;
|
|
234
|
+
user: PublicKey;
|
|
235
|
+
recipient?: PublicKey;
|
|
236
|
+
}): Promise<string> {
|
|
237
|
+
const [gatePda] = await findGatePda(params.gateId);
|
|
238
|
+
const [checkRecordPda] = await findCheckRecordPda(gatePda, params.user);
|
|
239
|
+
const recipient = params.recipient ?? this.provider.wallet.publicKey;
|
|
240
|
+
|
|
241
|
+
return this.program.methods
|
|
242
|
+
.closeCheckRecord(params.gateId)
|
|
243
|
+
.accounts({
|
|
244
|
+
gate: gatePda,
|
|
245
|
+
user: params.user,
|
|
246
|
+
checkRecord: checkRecordPda,
|
|
247
|
+
authority: this.provider.wallet.publicKey,
|
|
248
|
+
recipient,
|
|
249
|
+
})
|
|
250
|
+
.rpc();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ─────────────────────────────────────────────────────
|
|
254
|
+
// FETCH ACCOUNTS
|
|
255
|
+
// ─────────────────────────────────────────────────────
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Fetch a Gate account.
|
|
259
|
+
*/
|
|
260
|
+
async fetchGate(gateId: PublicKey): Promise<Gate | null> {
|
|
261
|
+
const [gatePda] = await findGatePda(gateId);
|
|
262
|
+
try {
|
|
263
|
+
return (await this.program.account.Gate.fetch(gatePda)) as unknown as Gate;
|
|
264
|
+
} catch {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Fetch a GateCheckRecord for a user.
|
|
271
|
+
*/
|
|
272
|
+
async fetchCheckRecord(
|
|
273
|
+
gateId: PublicKey,
|
|
274
|
+
user: PublicKey
|
|
275
|
+
): Promise<GateCheckRecord | null> {
|
|
276
|
+
const [gatePda] = await findGatePda(gateId);
|
|
277
|
+
const [checkRecordPda] = await findCheckRecordPda(gatePda, user);
|
|
278
|
+
try {
|
|
279
|
+
return (await this.program.account.GateCheckRecord.fetch(
|
|
280
|
+
checkRecordPda
|
|
281
|
+
)) as unknown as GateCheckRecord;
|
|
282
|
+
} catch {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Fetch all gates owned by a specific authority.
|
|
289
|
+
*/
|
|
290
|
+
async fetchGatesByAuthority(authority: PublicKey): Promise<
|
|
291
|
+
{ publicKey: PublicKey; account: Gate }[]
|
|
292
|
+
> {
|
|
293
|
+
const accounts = await this.program.account.Gate.all([
|
|
294
|
+
{
|
|
295
|
+
memcmp: {
|
|
296
|
+
offset: 8 + 1 + 32, // discriminator + version + gateId
|
|
297
|
+
bytes: authority.toBase58(),
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
]);
|
|
301
|
+
return accounts as unknown as { publicKey: PublicKey; account: Gate }[];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ─────────────────────────────────────────────────────
|
|
305
|
+
// INSTRUCTION BUILDERS (for composing with other txns)
|
|
306
|
+
// ─────────────────────────────────────────────────────
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Returns the raw instruction for checkGate — useful for
|
|
310
|
+
* bundling into a larger transaction (e.g., CPI-style on client side).
|
|
311
|
+
*/
|
|
312
|
+
async buildCheckGateInstruction(
|
|
313
|
+
params: CheckGateParams
|
|
314
|
+
): Promise<TransactionInstruction> {
|
|
315
|
+
const [gatePda] = await findGatePda(params.gateId);
|
|
316
|
+
const [checkRecordPda] = params.storeRecord
|
|
317
|
+
? await findCheckRecordPda(gatePda, params.user)
|
|
318
|
+
: [null];
|
|
319
|
+
|
|
320
|
+
return this.program.methods
|
|
321
|
+
.checkGate(params.gateId)
|
|
322
|
+
.accounts({
|
|
323
|
+
gate: gatePda,
|
|
324
|
+
user: params.user,
|
|
325
|
+
reputationAccount: params.reputationAccount ?? null,
|
|
326
|
+
identityAccount: params.identityAccount ?? null,
|
|
327
|
+
linkAccount: params.linkAccount ?? null,
|
|
328
|
+
tokenAccount: params.tokenAccount ?? null,
|
|
329
|
+
checkRecord: checkRecordPda ?? null,
|
|
330
|
+
payer: this.provider.wallet.publicKey,
|
|
331
|
+
systemProgram: SystemProgram.programId,
|
|
332
|
+
})
|
|
333
|
+
.instruction();
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Build a full transaction that checks a gate and then executes
|
|
338
|
+
* additional instructions (e.g., mint, vote, transfer).
|
|
339
|
+
*/
|
|
340
|
+
async buildGatedTransaction(
|
|
341
|
+
checkParams: CheckGateParams,
|
|
342
|
+
...additionalInstructions: TransactionInstruction[]
|
|
343
|
+
): Promise<Transaction> {
|
|
344
|
+
const checkIx = await this.buildCheckGateInstruction(checkParams);
|
|
345
|
+
const tx = new Transaction();
|
|
346
|
+
tx.add(checkIx, ...additionalInstructions);
|
|
347
|
+
return tx;
|
|
348
|
+
}
|
|
349
|
+
}
|