@glowlabs-org/utils 0.2.154 → 0.2.156
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 +175 -17
- package/dist/cjs/browser.d.ts +2 -0
- package/dist/cjs/browser.js +7 -1
- package/dist/cjs/browser.js.map +1 -1
- package/dist/cjs/{farms-router-DwbBMkUd.js → farms-router-DekpTBQj.js} +750 -11
- package/dist/cjs/farms-router-DekpTBQj.js.map +1 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/abis/rewardKernelABI.d.ts +418 -0
- package/dist/cjs/lib/control-api/farms-router.d.ts +2 -1
- package/dist/cjs/lib/control-api/region-router.d.ts +2 -1
- package/dist/cjs/lib/control-api/wallets-router.d.ts +2 -2
- package/dist/cjs/lib/hooks/use-rewards-kernel.d.ts +45 -0
- package/dist/cjs/lib/types/index.d.ts +77 -1
- package/dist/esm/browser.d.ts +2 -0
- package/dist/esm/browser.js +2 -2
- package/dist/esm/{farms-router-C0g4hf2Z.js → farms-router-L56VPDNz.js} +749 -12
- package/dist/esm/farms-router-L56VPDNz.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/lib/abis/rewardKernelABI.d.ts +418 -0
- package/dist/esm/lib/control-api/farms-router.d.ts +2 -1
- package/dist/esm/lib/control-api/region-router.d.ts +2 -1
- package/dist/esm/lib/control-api/wallets-router.d.ts +2 -2
- package/dist/esm/lib/hooks/use-rewards-kernel.d.ts +45 -0
- package/dist/esm/lib/types/index.d.ts +77 -1
- package/package.json +1 -1
- package/src/browser.ts +2 -0
- package/src/index.ts +1 -0
- package/src/lib/abis/rewardKernelABI.ts +264 -0
- package/src/lib/control-api/farms-router.ts +33 -0
- package/src/lib/control-api/region-router.ts +29 -0
- package/src/lib/control-api/wallets-router.ts +36 -2
- package/src/lib/hooks/README.md +295 -0
- package/src/lib/hooks/use-rewards-kernel.ts +547 -0
- package/src/lib/types/index.ts +91 -1
- package/dist/cjs/farms-router-DwbBMkUd.js.map +0 -1
- package/dist/esm/farms-router-C0g4hf2Z.js.map +0 -1
package/src/lib/hooks/README.md
CHANGED
|
@@ -284,3 +284,298 @@ async function createAndBuyFraction() {
|
|
|
284
284
|
```
|
|
285
285
|
|
|
286
286
|
This hook provides a complete interface for managing fractional token sales on the Glow protocol, with built-in error handling, gas estimation, and type safety.
|
|
287
|
+
|
|
288
|
+
## useRewardsKernel
|
|
289
|
+
|
|
290
|
+
The `useRewardsKernel` hook provides functionality for claiming rewards from the Glow Foundation's Merkle-tree based reward distribution system. This contract enables secure, verifiable token distributions with support for both regular and guarded tokens.
|
|
291
|
+
|
|
292
|
+
### Key Concepts
|
|
293
|
+
|
|
294
|
+
**1. Merkle-tree Based Distribution**
|
|
295
|
+
|
|
296
|
+
- Rewards are distributed using Merkle proofs to ensure only eligible users can claim
|
|
297
|
+
- Each distribution has a unique nonce and merkle root
|
|
298
|
+
- Users provide proof of their eligibility when claiming
|
|
299
|
+
|
|
300
|
+
**2. Finality Period**
|
|
301
|
+
|
|
302
|
+
- After a reward root is posted, there's a finality period before claims can begin
|
|
303
|
+
- During this period, the rejection multisig can reject problematic distributions
|
|
304
|
+
- Once finalized, rewards become claimable
|
|
305
|
+
|
|
306
|
+
**3. Guarded Tokens**
|
|
307
|
+
|
|
308
|
+
- Some tokens have transfer restrictions (only transferable between EOAs and allowlisted contracts)
|
|
309
|
+
- The contract uses a CounterfactualHolderFactory to handle these special tokens
|
|
310
|
+
- Users can choose to receive guarded tokens to a counterfactual wallet
|
|
311
|
+
|
|
312
|
+
**4. Security Model**
|
|
313
|
+
|
|
314
|
+
- Foundation multisig posts reward roots (admin function - not included in this hook)
|
|
315
|
+
- Rejection multisig can reject roots within finality period (admin function - not included)
|
|
316
|
+
- Hot wallet holds the actual tokens and must approve the contract
|
|
317
|
+
- No custodied funds - tokens remain with the hot wallet until claimed
|
|
318
|
+
|
|
319
|
+
### Setup
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
import { useRewardsKernel } from "@glowlabs-org/utils";
|
|
323
|
+
import { createWalletClient, createPublicClient, http } from "viem";
|
|
324
|
+
import { mainnet } from "viem/chains";
|
|
325
|
+
|
|
326
|
+
// Initialize clients
|
|
327
|
+
const walletClient = createWalletClient({
|
|
328
|
+
chain: mainnet,
|
|
329
|
+
transport: http(),
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const publicClient = createPublicClient({
|
|
333
|
+
chain: mainnet,
|
|
334
|
+
transport: http(),
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
const CHAIN_ID = 1; // Ethereum mainnet
|
|
338
|
+
const rewardsKernel = useRewardsKernel(walletClient, publicClient, CHAIN_ID);
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Core Features
|
|
342
|
+
|
|
343
|
+
#### 1. Claiming Rewards
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import { ClaimPayoutParams } from "@glowlabs-org/utils";
|
|
347
|
+
|
|
348
|
+
const claimParams: ClaimPayoutParams = {
|
|
349
|
+
nonce: 1n, // The distribution nonce
|
|
350
|
+
proof: [
|
|
351
|
+
"0x1234567890abcdef...", // Merkle proof elements
|
|
352
|
+
"0xabcdef1234567890...",
|
|
353
|
+
],
|
|
354
|
+
tokensAndAmounts: [
|
|
355
|
+
{
|
|
356
|
+
token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
|
357
|
+
amount: 1000000n, // 1 USDC (6 decimals)
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
token: "0xf4fbC617A5733EAAF9af08E1Ab816B103388d8B6", // GLW
|
|
361
|
+
amount: 1000000000000000000n, // 1 GLW (18 decimals)
|
|
362
|
+
},
|
|
363
|
+
],
|
|
364
|
+
from: "0xHotWalletAddress...", // Address holding the tokens
|
|
365
|
+
to: "0xYourAddress...", // Where you want to receive tokens
|
|
366
|
+
isGuardedToken: [false, true], // USDC is not guarded, GLW is guarded
|
|
367
|
+
toCounterfactual: [false, false], // Send both to regular address
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
const txHash = await rewardsKernel.claimPayout(claimParams);
|
|
372
|
+
console.log("Rewards claimed:", txHash);
|
|
373
|
+
} catch (error) {
|
|
374
|
+
console.error("Claim failed:", error.message);
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Data Retrieval
|
|
379
|
+
|
|
380
|
+
#### Check Reward Status
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
// Get reward metadata for a nonce
|
|
384
|
+
const rewardMeta = await rewardsKernel.getRewardMeta(1n);
|
|
385
|
+
console.log({
|
|
386
|
+
merkleRoot: rewardMeta.merkleRoot,
|
|
387
|
+
pushTimestamp: rewardMeta.pushTimestamp,
|
|
388
|
+
rejected: rewardMeta.rejected,
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// Check if nonce is finalized and claimable
|
|
392
|
+
const isFinalized = await rewardsKernel.isFinalized(1n);
|
|
393
|
+
console.log("Can claim:", isFinalized);
|
|
394
|
+
|
|
395
|
+
// Check if user already claimed
|
|
396
|
+
const userAddress = "0xYourAddress...";
|
|
397
|
+
const hasClaimed = await rewardsKernel.isClaimed(userAddress, 1n);
|
|
398
|
+
console.log("Already claimed:", hasClaimed);
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
#### Check Token Amounts
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
const nonce = 1n;
|
|
405
|
+
const usdcAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
|
406
|
+
|
|
407
|
+
// Get maximum claimable amount for a token
|
|
408
|
+
const maxReward = await rewardsKernel.getMaxReward(nonce, usdcAddress);
|
|
409
|
+
console.log("Max USDC claimable:", maxReward);
|
|
410
|
+
|
|
411
|
+
// Get amount already claimed
|
|
412
|
+
const amountClaimed = await rewardsKernel.getAmountClaimed(nonce, usdcAddress);
|
|
413
|
+
console.log("USDC already claimed:", amountClaimed);
|
|
414
|
+
|
|
415
|
+
// Calculate remaining claimable
|
|
416
|
+
const remaining = maxReward - amountClaimed;
|
|
417
|
+
console.log("USDC remaining:", remaining);
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Contract Configuration
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
// Get finality period (in seconds)
|
|
424
|
+
const finality = await rewardsKernel.getFinality();
|
|
425
|
+
console.log(`Finality period: ${finality} seconds`);
|
|
426
|
+
|
|
427
|
+
// Get next nonce that will be used
|
|
428
|
+
const nextNonce = await rewardsKernel.getNextPostNonce();
|
|
429
|
+
console.log("Next nonce:", nextNonce);
|
|
430
|
+
|
|
431
|
+
// Get multisig addresses
|
|
432
|
+
const foundationMultisig = await rewardsKernel.getFoundationMultisig();
|
|
433
|
+
const rejectionMultisig = await rewardsKernel.getRejectionMultisig();
|
|
434
|
+
console.log("Foundation:", foundationMultisig);
|
|
435
|
+
console.log("Rejection:", rejectionMultisig);
|
|
436
|
+
|
|
437
|
+
// Get counterfactual holder factory
|
|
438
|
+
const cfhFactory = await rewardsKernel.getCFHFactory();
|
|
439
|
+
console.log("CFH Factory:", cfhFactory);
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Gas Estimation
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
const ethPrice = 2000; // Current ETH price in USD
|
|
446
|
+
|
|
447
|
+
// Estimate gas for claiming
|
|
448
|
+
const claimCost = await rewardsKernel.estimateGasForClaimPayout(
|
|
449
|
+
claimParams,
|
|
450
|
+
ethPrice
|
|
451
|
+
);
|
|
452
|
+
console.log(`Claim cost: $${claimCost}`);
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Understanding the Merkle Proof
|
|
456
|
+
|
|
457
|
+
The merkle proof verifies your eligibility to claim specific amounts of tokens:
|
|
458
|
+
|
|
459
|
+
1. **Leaf Construction**: Your claim data is hashed as `keccak256(abi.encode(userAddress, tokensAndAmountsHash))`
|
|
460
|
+
2. **Proof Verification**: The proof elements allow reconstruction of the merkle root
|
|
461
|
+
3. **On-chain Validation**: The contract verifies your proof against the stored root
|
|
462
|
+
|
|
463
|
+
### Error Handling
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
import { RewardsKernelError } from "@glowlabs-org/utils";
|
|
467
|
+
|
|
468
|
+
try {
|
|
469
|
+
await rewardsKernel.claimPayout(params);
|
|
470
|
+
} catch (error) {
|
|
471
|
+
if (error.message === RewardsKernelError.ALREADY_CLAIMED) {
|
|
472
|
+
console.log("You've already claimed from this distribution");
|
|
473
|
+
} else if (error.message === RewardsKernelError.NOT_FINALIZED) {
|
|
474
|
+
console.log("Distribution not yet finalized, please wait");
|
|
475
|
+
} else if (error.message === RewardsKernelError.NONCE_REJECTED) {
|
|
476
|
+
console.log("This distribution was rejected");
|
|
477
|
+
}
|
|
478
|
+
// ... handle other errors
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
Available error types:
|
|
483
|
+
|
|
484
|
+
- `CONTRACT_NOT_AVAILABLE`
|
|
485
|
+
- `SIGNER_NOT_AVAILABLE`
|
|
486
|
+
- `UNKNOWN_ERROR`
|
|
487
|
+
- `INVALID_PARAMETERS`
|
|
488
|
+
- `ALREADY_CLAIMED`
|
|
489
|
+
- `NOT_FINALIZED`
|
|
490
|
+
- `NONCE_REJECTED`
|
|
491
|
+
|
|
492
|
+
### Best Practices
|
|
493
|
+
|
|
494
|
+
1. **Always check claim status** before attempting to claim
|
|
495
|
+
2. **Verify finalization** to avoid failed transactions
|
|
496
|
+
3. **Handle guarded tokens properly** - understand which tokens need special handling
|
|
497
|
+
4. **Validate merkle proofs** off-chain before submitting transactions
|
|
498
|
+
5. **Monitor gas prices** for optimal claiming times
|
|
499
|
+
|
|
500
|
+
### Example: Complete Claim Flow
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
async function claimRewards(nonce: bigint, proof: string[], claimData: any) {
|
|
504
|
+
const rewardsKernel = useRewardsKernel(walletClient, publicClient, CHAIN_ID);
|
|
505
|
+
|
|
506
|
+
try {
|
|
507
|
+
// 1. Check if nonce exists and is valid
|
|
508
|
+
const meta = await rewardsKernel.getRewardMeta(nonce);
|
|
509
|
+
if (meta.rejected) {
|
|
510
|
+
throw new Error("This distribution was rejected");
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// 2. Check if finalized
|
|
514
|
+
const finalized = await rewardsKernel.isFinalized(nonce);
|
|
515
|
+
if (!finalized) {
|
|
516
|
+
const finalityPeriod = await rewardsKernel.getFinality();
|
|
517
|
+
const timeRemaining =
|
|
518
|
+
Number(meta.pushTimestamp) + Number(finalityPeriod) - Date.now() / 1000;
|
|
519
|
+
throw new Error(`Not finalized yet. Wait ${timeRemaining} seconds`);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// 3. Check if already claimed
|
|
523
|
+
const userAddress = await walletClient.account.address;
|
|
524
|
+
const claimed = await rewardsKernel.isClaimed(userAddress, nonce);
|
|
525
|
+
if (claimed) {
|
|
526
|
+
throw new Error("Already claimed from this distribution");
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// 4. Verify amounts are still available
|
|
530
|
+
for (const tokenAmount of claimData.tokensAndAmounts) {
|
|
531
|
+
const maxReward = await rewardsKernel.getMaxReward(
|
|
532
|
+
nonce,
|
|
533
|
+
tokenAmount.token
|
|
534
|
+
);
|
|
535
|
+
const claimed = await rewardsKernel.getAmountClaimed(
|
|
536
|
+
nonce,
|
|
537
|
+
tokenAmount.token
|
|
538
|
+
);
|
|
539
|
+
const remaining = maxReward - claimed;
|
|
540
|
+
|
|
541
|
+
if (remaining < tokenAmount.amount) {
|
|
542
|
+
throw new Error(`Insufficient ${tokenAmount.token} remaining`);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// 5. Estimate gas
|
|
547
|
+
const gasEstimate = await rewardsKernel.estimateGasForClaimPayout(
|
|
548
|
+
claimData,
|
|
549
|
+
2000 // current ETH price
|
|
550
|
+
);
|
|
551
|
+
console.log(`Estimated cost: $${gasEstimate}`);
|
|
552
|
+
|
|
553
|
+
// 6. Execute claim
|
|
554
|
+
const txHash = await rewardsKernel.claimPayout(claimData);
|
|
555
|
+
console.log("Success! Transaction:", txHash);
|
|
556
|
+
} catch (error) {
|
|
557
|
+
console.error("Claim failed:", error.message);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### Working with Guarded Tokens
|
|
563
|
+
|
|
564
|
+
Guarded tokens (like GLW) have transfer restrictions. Here's how to handle them:
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
// Option 1: Receive to counterfactual wallet
|
|
568
|
+
const claimToCounterfactual = {
|
|
569
|
+
...claimParams,
|
|
570
|
+
toCounterfactual: [false, true], // GLW goes to counterfactual
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
// Option 2: Check if your address can receive guarded tokens
|
|
574
|
+
// (This would require checking with the token contract's allowlist)
|
|
575
|
+
|
|
576
|
+
// The counterfactual wallet address can be computed:
|
|
577
|
+
const cfhFactory = await rewardsKernel.getCFHFactory();
|
|
578
|
+
// The CFH factory will create/use a deterministic address for your wallet + token
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
This hook provides a secure interface for claiming rewards from the Glow Foundation's distribution system, with full support for both regular and guarded tokens, comprehensive error handling, and gas estimation.
|