pepay-streams-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.
Files changed (62) hide show
  1. package/README.md +405 -0
  2. package/dist/api/index.d.mts +321 -0
  3. package/dist/api/index.d.ts +321 -0
  4. package/dist/api/index.js +312 -0
  5. package/dist/api/index.js.map +1 -0
  6. package/dist/api/index.mjs +306 -0
  7. package/dist/api/index.mjs.map +1 -0
  8. package/dist/automation/index.d.mts +140 -0
  9. package/dist/automation/index.d.ts +140 -0
  10. package/dist/automation/index.js +331 -0
  11. package/dist/automation/index.js.map +1 -0
  12. package/dist/automation/index.mjs +326 -0
  13. package/dist/automation/index.mjs.map +1 -0
  14. package/dist/campaigns/index.d.mts +286 -0
  15. package/dist/campaigns/index.d.ts +286 -0
  16. package/dist/campaigns/index.js +652 -0
  17. package/dist/campaigns/index.js.map +1 -0
  18. package/dist/campaigns/index.mjs +645 -0
  19. package/dist/campaigns/index.mjs.map +1 -0
  20. package/dist/claims/index.d.mts +190 -0
  21. package/dist/claims/index.d.ts +190 -0
  22. package/dist/claims/index.js +414 -0
  23. package/dist/claims/index.js.map +1 -0
  24. package/dist/claims/index.mjs +409 -0
  25. package/dist/claims/index.mjs.map +1 -0
  26. package/dist/index-BTG0TRJt.d.mts +555 -0
  27. package/dist/index-BTG0TRJt.d.ts +555 -0
  28. package/dist/index.d.mts +170 -0
  29. package/dist/index.d.ts +170 -0
  30. package/dist/index.js +2926 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/index.mjs +2888 -0
  33. package/dist/index.mjs.map +1 -0
  34. package/dist/marketplace/index.d.mts +225 -0
  35. package/dist/marketplace/index.d.ts +225 -0
  36. package/dist/marketplace/index.js +529 -0
  37. package/dist/marketplace/index.js.map +1 -0
  38. package/dist/marketplace/index.mjs +524 -0
  39. package/dist/marketplace/index.mjs.map +1 -0
  40. package/dist/react/index.d.mts +185 -0
  41. package/dist/react/index.d.ts +185 -0
  42. package/dist/react/index.js +340 -0
  43. package/dist/react/index.js.map +1 -0
  44. package/dist/react/index.mjs +333 -0
  45. package/dist/react/index.mjs.map +1 -0
  46. package/dist/staking/index.d.mts +158 -0
  47. package/dist/staking/index.d.ts +158 -0
  48. package/dist/staking/index.js +359 -0
  49. package/dist/staking/index.js.map +1 -0
  50. package/dist/staking/index.mjs +354 -0
  51. package/dist/staking/index.mjs.map +1 -0
  52. package/package.json +106 -0
  53. package/src/api/index.ts +577 -0
  54. package/src/automation/index.ts +436 -0
  55. package/src/campaigns/index.ts +835 -0
  56. package/src/claims/index.ts +530 -0
  57. package/src/client.ts +518 -0
  58. package/src/index.ts +101 -0
  59. package/src/marketplace/index.ts +730 -0
  60. package/src/react/index.ts +498 -0
  61. package/src/staking/index.ts +449 -0
  62. package/src/types/index.ts +631 -0
@@ -0,0 +1,530 @@
1
+ /**
2
+ * Claims Module
3
+ *
4
+ * Provides methods for claiming tokens from campaigns:
5
+ * - Single claims (with merkle proof)
6
+ * - Batch claims
7
+ * - Meta-transaction (gasless) claims
8
+ * - Lock releases
9
+ */
10
+ import {
11
+ type PublicClient,
12
+ type WalletClient,
13
+ type Address,
14
+ type Hash,
15
+ type Hex,
16
+ keccak256,
17
+ encodePacked,
18
+ } from 'viem';
19
+ import { DIAMOND_ABI } from '@pepay-streams/abi/diamond';
20
+ import type {
21
+ ClaimParams,
22
+ BatchClaimParams,
23
+ MetaClaimParams,
24
+ RecipientStatus,
25
+ TransactionResult,
26
+ } from '../types';
27
+
28
+ /**
29
+ * EIP-712 domain for meta-transaction signatures
30
+ */
31
+ interface EIP712Domain {
32
+ name: string;
33
+ version: string;
34
+ chainId: number;
35
+ verifyingContract: Address;
36
+ }
37
+
38
+ /**
39
+ * Claims module for claiming tokens from distribution campaigns
40
+ */
41
+ export class ClaimsModule {
42
+ constructor(
43
+ private readonly publicClient: PublicClient,
44
+ private readonly walletClient: WalletClient | undefined,
45
+ private readonly diamondAddress: Address,
46
+ private readonly chainId: number
47
+ ) {}
48
+
49
+ // ============================================================================
50
+ // Standard Claims
51
+ // ============================================================================
52
+
53
+ /**
54
+ * Claim vested tokens from a campaign
55
+ *
56
+ * For merkle-tree campaigns, requires allocation and proof.
57
+ * For direct campaigns, allocation should be 0 and proof empty.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * // Direct campaign claim
62
+ * const result = await sdk.claims.claim({
63
+ * campaignId: 1n,
64
+ * allocation: 0n,
65
+ * proof: [],
66
+ * });
67
+ *
68
+ * // Merkle campaign claim
69
+ * const result = await sdk.claims.claim({
70
+ * campaignId: 1n,
71
+ * allocation: parseEther('100'),
72
+ * proof: ['0x...', '0x...'],
73
+ * });
74
+ * ```
75
+ */
76
+ async claim(params: ClaimParams): Promise<TransactionResult> {
77
+ const wallet = this.requireWallet();
78
+
79
+ let hash: Hash;
80
+
81
+ if (params.claimTo) {
82
+ hash = await wallet.writeContract({
83
+ chain: wallet.chain,
84
+ account: wallet.account!,
85
+ address: this.diamondAddress,
86
+ abi: DIAMOND_ABI,
87
+ functionName: 'claimTo',
88
+ args: [
89
+ params.campaignId,
90
+ params.claimTo,
91
+ params.allocation ?? 0n,
92
+ params.proof ?? [],
93
+ ],
94
+ });
95
+ } else {
96
+ hash = await wallet.writeContract({
97
+ chain: wallet.chain,
98
+ account: wallet.account!,
99
+ address: this.diamondAddress,
100
+ abi: DIAMOND_ABI,
101
+ functionName: 'claim',
102
+ args: [
103
+ params.campaignId,
104
+ params.allocation ?? 0n,
105
+ params.proof ?? [],
106
+ ],
107
+ });
108
+ }
109
+
110
+ return this.createTransactionResult(hash);
111
+ }
112
+
113
+ /**
114
+ * Claim from a campaign for multiple recipients in a single transaction
115
+ *
116
+ * More gas efficient than multiple individual claims.
117
+ * For direct allocation campaigns only.
118
+ *
119
+ * @example
120
+ * ```typescript
121
+ * const result = await sdk.claims.claimBatch({
122
+ * campaignId: 1n,
123
+ * recipients: ['0x...', '0x...', '0x...'],
124
+ * });
125
+ * ```
126
+ */
127
+ async claimBatch(params: BatchClaimParams): Promise<TransactionResult> {
128
+ const wallet = this.requireWallet();
129
+
130
+ const hash = await wallet.writeContract({
131
+ chain: wallet.chain,
132
+ account: wallet.account!,
133
+ address: this.diamondAddress,
134
+ abi: DIAMOND_ABI,
135
+ functionName: 'claimMany',
136
+ args: [params.campaignId, params.recipients],
137
+ });
138
+
139
+ return this.createTransactionResult(hash);
140
+ }
141
+
142
+ /**
143
+ * Release locked tokens (for Lock campaigns)
144
+ *
145
+ * Can only be called after the unlock time has passed.
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * const result = await sdk.claims.releaseLock(campaignId, [recipient1, recipient2]);
150
+ * ```
151
+ */
152
+ async releaseLock(
153
+ campaignId: bigint,
154
+ recipients: Address[]
155
+ ): Promise<TransactionResult> {
156
+ const wallet = this.requireWallet();
157
+
158
+ const hash = await wallet.writeContract({
159
+ chain: wallet.chain,
160
+ account: wallet.account!,
161
+ address: this.diamondAddress,
162
+ abi: DIAMOND_ABI,
163
+ functionName: 'releaseLock',
164
+ args: [campaignId, recipients],
165
+ });
166
+
167
+ return this.createTransactionResult(hash);
168
+ }
169
+
170
+ // ============================================================================
171
+ // Meta-Transaction Claims (Gasless)
172
+ // ============================================================================
173
+
174
+ /**
175
+ * Claim via meta-transaction (gasless for recipient)
176
+ *
177
+ * A relayer submits the transaction on behalf of the recipient.
178
+ * The recipient signs an EIP-712 message off-chain.
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * // Recipient signs off-chain
183
+ * const signedAuth = await sdk.claims.signClaimMessage({
184
+ * campaignId,
185
+ * allocation: parseEther('100'),
186
+ * proof: ['0x...'],
187
+ * deadline: Math.floor(Date.now() / 1000) + 3600, // 1 hour
188
+ * });
189
+ *
190
+ * // Relayer submits
191
+ * const result = await sdk.claims.claimWithSig(signedAuth);
192
+ * ```
193
+ */
194
+ async claimWithSig(params: MetaClaimParams): Promise<TransactionResult> {
195
+ const wallet = this.requireWallet();
196
+
197
+ const auth = {
198
+ id: params.campaignId,
199
+ claimant: params.claimant,
200
+ payoutTo: params.payoutTo ?? params.claimant,
201
+ allocation: params.allocation,
202
+ proofHash: this.computeProofHash(params.proof),
203
+ deadline: BigInt(params.deadline),
204
+ nonce: params.nonce,
205
+ };
206
+
207
+ const hash = await wallet.writeContract({
208
+ chain: wallet.chain,
209
+ account: wallet.account!,
210
+ address: this.diamondAddress,
211
+ abi: DIAMOND_ABI,
212
+ functionName: 'claimWithSig',
213
+ args: [auth, params.proof, params.signature] as const,
214
+ });
215
+
216
+ return this.createTransactionResult(hash);
217
+ }
218
+
219
+ /**
220
+ * Generate the EIP-712 typed data for a claim signature
221
+ *
222
+ * The recipient signs this message off-chain.
223
+ */
224
+ getClaimTypedData(
225
+ campaignId: bigint,
226
+ claimant: Address,
227
+ payoutTo: Address,
228
+ allocation: bigint,
229
+ proofHash: Hex,
230
+ nonce: bigint,
231
+ deadline: number
232
+ ): {
233
+ domain: EIP712Domain;
234
+ types: Record<string, { name: string; type: string }[]>;
235
+ primaryType: string;
236
+ message: Record<string, unknown>;
237
+ } {
238
+ return {
239
+ domain: {
240
+ name: 'PepayStreams',
241
+ version: '1',
242
+ chainId: this.chainId,
243
+ verifyingContract: this.diamondAddress,
244
+ },
245
+ types: {
246
+ ClaimAuth: [
247
+ { name: 'id', type: 'uint256' },
248
+ { name: 'claimant', type: 'address' },
249
+ { name: 'payoutTo', type: 'address' },
250
+ { name: 'allocation', type: 'uint128' },
251
+ { name: 'proofHash', type: 'bytes32' },
252
+ { name: 'deadline', type: 'uint64' },
253
+ { name: 'nonce', type: 'uint256' },
254
+ ],
255
+ },
256
+ primaryType: 'ClaimAuth',
257
+ message: {
258
+ id: campaignId,
259
+ claimant,
260
+ payoutTo,
261
+ allocation,
262
+ proofHash,
263
+ deadline: BigInt(deadline),
264
+ nonce,
265
+ },
266
+ };
267
+ }
268
+
269
+ /**
270
+ * Sign a claim message for meta-transaction
271
+ *
272
+ * Returns the signature that can be submitted by a relayer.
273
+ */
274
+ async signClaimMessage(params: {
275
+ campaignId: bigint;
276
+ allocation: bigint;
277
+ proof: Hex[];
278
+ deadline: number;
279
+ payoutTo?: Address;
280
+ }): Promise<{
281
+ signature: Hex;
282
+ nonce: bigint;
283
+ deadline: number;
284
+ claimant: Address;
285
+ payoutTo: Address;
286
+ allocation: bigint;
287
+ proof: Hex[];
288
+ campaignId: bigint;
289
+ }> {
290
+ const wallet = this.requireWallet();
291
+ const claimant = wallet.account!.address;
292
+ const payoutTo = params.payoutTo ?? claimant;
293
+
294
+ // Get current nonce
295
+ const nonce = await this.getClaimNonce(params.campaignId, claimant);
296
+ const proofHash = this.computeProofHash(params.proof);
297
+
298
+ const typedData = this.getClaimTypedData(
299
+ params.campaignId,
300
+ claimant,
301
+ payoutTo,
302
+ params.allocation,
303
+ proofHash,
304
+ nonce,
305
+ params.deadline
306
+ );
307
+
308
+ const signature = await wallet.signTypedData({
309
+ account: wallet.account!,
310
+ domain: typedData.domain,
311
+ types: typedData.types,
312
+ primaryType: typedData.primaryType as 'ClaimAuth',
313
+ message: typedData.message,
314
+ });
315
+
316
+ return {
317
+ signature,
318
+ nonce,
319
+ deadline: params.deadline,
320
+ claimant,
321
+ payoutTo,
322
+ allocation: params.allocation,
323
+ proof: params.proof,
324
+ campaignId: params.campaignId,
325
+ };
326
+ }
327
+
328
+ /**
329
+ * Get the current nonce for claim meta-transactions
330
+ */
331
+ async getClaimNonce(campaignId: bigint, address: Address): Promise<bigint> {
332
+ const result = await this.publicClient.readContract({
333
+ address: this.diamondAddress,
334
+ abi: DIAMOND_ABI,
335
+ functionName: 'noncesClaim',
336
+ args: [campaignId, address],
337
+ });
338
+
339
+ return result as bigint;
340
+ }
341
+
342
+ // ============================================================================
343
+ // Claim Status Queries
344
+ // ============================================================================
345
+
346
+ /**
347
+ * Get the amount currently claimable for a recipient
348
+ *
349
+ * @example
350
+ * ```typescript
351
+ * const claimable = await sdk.claims.getClaimable(campaignId, recipientAddress);
352
+ * console.log('Claimable:', formatEther(claimable));
353
+ * ```
354
+ */
355
+ async getClaimable(campaignId: bigint, recipient: Address): Promise<bigint> {
356
+ const result = await this.publicClient.readContract({
357
+ address: this.diamondAddress,
358
+ abi: DIAMOND_ABI,
359
+ functionName: 'claimableOf',
360
+ args: [campaignId, recipient],
361
+ });
362
+
363
+ return result as bigint;
364
+ }
365
+
366
+ /**
367
+ * Check if a recipient is blocked from claiming
368
+ */
369
+ async isBlocked(campaignId: bigint, recipient: Address): Promise<boolean> {
370
+ const result = await this.publicClient.readContract({
371
+ address: this.diamondAddress,
372
+ abi: DIAMOND_ABI,
373
+ functionName: 'isBlocked',
374
+ args: [campaignId, recipient],
375
+ });
376
+
377
+ return result as boolean;
378
+ }
379
+
380
+ /**
381
+ * Get vested amount for a recipient (how much has vested so far)
382
+ */
383
+ async getVestedAmount(
384
+ campaignId: bigint,
385
+ recipient: Address,
386
+ allocation: bigint
387
+ ): Promise<bigint> {
388
+ const result = await this.publicClient.readContract({
389
+ address: this.diamondAddress,
390
+ abi: DIAMOND_ABI,
391
+ functionName: 'vestedAmount',
392
+ args: [campaignId, recipient, allocation],
393
+ });
394
+
395
+ return result as bigint;
396
+ }
397
+
398
+ /**
399
+ * Get merkle claimed shares for a recipient
400
+ */
401
+ async getMerkleClaimedShares(
402
+ campaignId: bigint,
403
+ recipient: Address
404
+ ): Promise<bigint> {
405
+ const result = await this.publicClient.readContract({
406
+ address: this.diamondAddress,
407
+ abi: DIAMOND_ABI,
408
+ functionName: 'merkleClaimedShares',
409
+ args: [campaignId, recipient],
410
+ });
411
+
412
+ return result as bigint;
413
+ }
414
+
415
+ /**
416
+ * Get detailed recipient status for a campaign
417
+ */
418
+ async getRecipientStatus(
419
+ campaignId: bigint,
420
+ recipient: Address,
421
+ allocation: bigint
422
+ ): Promise<RecipientStatus> {
423
+ const [claimable, blocked, vested, claimed] = await Promise.all([
424
+ this.getClaimable(campaignId, recipient),
425
+ this.isBlocked(campaignId, recipient),
426
+ this.getVestedAmount(campaignId, recipient, allocation),
427
+ this.getMerkleClaimedShares(campaignId, recipient),
428
+ ]);
429
+
430
+ return {
431
+ allocated: allocation,
432
+ claimed,
433
+ due: claimable,
434
+ blocked,
435
+ fullyVested: vested >= allocation,
436
+ };
437
+ }
438
+
439
+ /**
440
+ * Check if a recipient can claim from a campaign
441
+ */
442
+ async canClaim(campaignId: bigint, recipient: Address): Promise<boolean> {
443
+ try {
444
+ const [claimable, blocked] = await Promise.all([
445
+ this.getClaimable(campaignId, recipient),
446
+ this.isBlocked(campaignId, recipient),
447
+ ]);
448
+ return claimable > 0n && !blocked;
449
+ } catch {
450
+ return false;
451
+ }
452
+ }
453
+
454
+ // ============================================================================
455
+ // Merkle Proof Helpers
456
+ // ============================================================================
457
+
458
+ /**
459
+ * Verify a Merkle proof locally
460
+ *
461
+ * Useful for validating proofs before submitting transactions.
462
+ */
463
+ verifyMerkleProof(root: Hex, leaf: Hex, proof: Hex[]): boolean {
464
+ let computedHash = leaf;
465
+
466
+ for (const proofElement of proof) {
467
+ if (computedHash < proofElement) {
468
+ computedHash = keccak256(
469
+ encodePacked(['bytes32', 'bytes32'], [computedHash, proofElement])
470
+ );
471
+ } else {
472
+ computedHash = keccak256(
473
+ encodePacked(['bytes32', 'bytes32'], [proofElement, computedHash])
474
+ );
475
+ }
476
+ }
477
+
478
+ return computedHash === root;
479
+ }
480
+
481
+ /**
482
+ * Compute Merkle leaf for an allocation
483
+ */
484
+ computeMerkleLeaf(address: Address, amount: bigint): Hex {
485
+ return keccak256(encodePacked(['address', 'uint256'], [address, amount]));
486
+ }
487
+
488
+ /**
489
+ * Compute proof hash for meta-transaction
490
+ */
491
+ computeProofHash(proof: Hex[]): Hex {
492
+ if (proof.length === 0) {
493
+ return '0x0000000000000000000000000000000000000000000000000000000000000000';
494
+ }
495
+ return keccak256(encodePacked(['bytes32[]'], [proof]));
496
+ }
497
+
498
+ // ============================================================================
499
+ // Helpers
500
+ // ============================================================================
501
+
502
+ private requireWallet(): WalletClient {
503
+ if (!this.walletClient) {
504
+ throw new Error(
505
+ 'Wallet client required for write operations. Initialize SDK with a signer.'
506
+ );
507
+ }
508
+ return this.walletClient;
509
+ }
510
+
511
+ private createTransactionResult(hash: Hash): TransactionResult {
512
+ return {
513
+ hash,
514
+ wait: async () => {
515
+ const receipt = await this.publicClient.waitForTransactionReceipt({
516
+ hash,
517
+ });
518
+ return {
519
+ blockNumber: receipt.blockNumber,
520
+ transactionHash: receipt.transactionHash,
521
+ gasUsed: receipt.gasUsed,
522
+ status: receipt.status,
523
+ logs: receipt.logs,
524
+ };
525
+ },
526
+ };
527
+ }
528
+ }
529
+
530
+ export default ClaimsModule;