@zemyth/raise-sdk 0.1.1 → 0.1.3

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 (47) hide show
  1. package/README.md +11 -9
  2. package/dist/accounts/index.cjs +531 -3
  3. package/dist/accounts/index.cjs.map +1 -1
  4. package/dist/accounts/index.d.cts +307 -2
  5. package/dist/accounts/index.d.ts +307 -2
  6. package/dist/accounts/index.js +503 -4
  7. package/dist/accounts/index.js.map +1 -1
  8. package/dist/constants/index.cjs +41 -3
  9. package/dist/constants/index.cjs.map +1 -1
  10. package/dist/constants/index.d.cts +38 -3
  11. package/dist/constants/index.d.ts +38 -3
  12. package/dist/constants/index.js +40 -4
  13. package/dist/constants/index.js.map +1 -1
  14. package/dist/index.cjs +2297 -361
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +566 -7
  17. package/dist/index.d.ts +566 -7
  18. package/dist/index.js +2279 -379
  19. package/dist/index.js.map +1 -1
  20. package/dist/instructions/index.cjs +783 -40
  21. package/dist/instructions/index.cjs.map +1 -1
  22. package/dist/instructions/index.d.cts +492 -6
  23. package/dist/instructions/index.d.ts +492 -6
  24. package/dist/instructions/index.js +762 -42
  25. package/dist/instructions/index.js.map +1 -1
  26. package/dist/pdas/index.cjs +163 -1
  27. package/dist/pdas/index.cjs.map +1 -1
  28. package/dist/pdas/index.d.cts +131 -1
  29. package/dist/pdas/index.d.ts +131 -1
  30. package/dist/pdas/index.js +151 -2
  31. package/dist/pdas/index.js.map +1 -1
  32. package/dist/types/index.cjs +9 -0
  33. package/dist/types/index.cjs.map +1 -1
  34. package/dist/types/index.d.cts +586 -3
  35. package/dist/types/index.d.ts +586 -3
  36. package/dist/types/index.js +9 -1
  37. package/dist/types/index.js.map +1 -1
  38. package/package.json +5 -3
  39. package/src/__tests__/dynamic-tokenomics.test.ts +358 -0
  40. package/src/accounts/index.ts +852 -1
  41. package/src/client.ts +1130 -1
  42. package/src/constants/index.ts +48 -2
  43. package/src/index.ts +58 -0
  44. package/src/instructions/index.ts +1383 -40
  45. package/src/pdas/index.ts +346 -0
  46. package/src/types/index.ts +698 -2
  47. package/src/utils/index.ts +90 -0
package/README.md CHANGED
@@ -79,13 +79,15 @@ const tx = await client.initializeProject({
79
79
  ],
80
80
  tokenomics: {
81
81
  totalSupply: new BN('1000000000000000'), // 1B tokens (with decimals)
82
- symbol: 'PROJ',
83
- investorAllocationBps: 2000, // 20%
84
- founderAllocationBps: 2000, // 20%
85
- lpAllocationBps: 3000, // 30%
86
- treasuryAllocationBps: 3000, // 30%
87
- cliffSeconds: new BN(15552000), // 6 months
88
- vestingSeconds: new BN(63072000), // 2 years
82
+ tokenSymbol: [80, 82, 79, 74, 0, 0, 0, 0], // 'PROJ' as byte array
83
+ investorAllocationBps: 4000, // 40%
84
+ founderAllocationBps: 4900, // 49% - sub-allocations (treasury, advisors, marketing) draw from this pool
85
+ lpTokenAllocationBps: 1000, // 10%
86
+ lpUsdcAllocationBps: 500, // 5% of raised USDC
87
+ zemythAllocationBps: 100, // 1% platform fee (minimum), vests per milestone
88
+ founderWallet: founderWallet.publicKey,
89
+ vestingDurationMonths: 24, // 2 years
90
+ cliffMonths: 6, // 6 month cliff
89
91
  },
90
92
  milestone1Deadline: new BN(Math.floor(Date.now() / 1000) + 90 * 24 * 60 * 60), // 90 days
91
93
  });
@@ -747,8 +749,8 @@ npm run clean
747
749
 
748
750
  ## Links
749
751
 
750
- - [GitHub Repository](https://github.com/zemyth/raise)
751
- - [Issue Tracker](https://github.com/zemyth/raise/issues)
752
+ - [GitHub Repository](https://github.com/zemyth-app/raise)
753
+ - [Issue Tracker](https://github.com/zemyth-app/raise/issues)
752
754
  - [npm Package](https://www.npmjs.com/package/@zemyth/raise-sdk)
753
755
 
754
756
  ## License
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var web3_js = require('@solana/web3.js');
4
3
  var anchor = require('@coral-xyz/anchor');
4
+ var web3_js = require('@solana/web3.js');
5
5
 
6
- // src/pdas/index.ts
6
+ // src/accounts/index.ts
7
7
 
8
8
  // src/constants/index.ts
9
9
  var SEEDS = {
@@ -13,7 +13,12 @@ var SEEDS = {
13
13
  VOTE: "vote",
14
14
  PIVOT: "pivot",
15
15
  TGE_ESCROW: "tge_escrow",
16
- ADMIN_CONFIG: "admin-config"};
16
+ ADMIN_CONFIG: "admin-config",
17
+ FUTURE_ROUND_STATE: "future_round_state",
18
+ // Multi-Round Fundraising seeds
19
+ FUNDING_ROUND: "funding_round",
20
+ INVESTOR_MS_VESTING: "investor_ms_vesting"
21
+ };
17
22
 
18
23
  // src/pdas/index.ts
19
24
  function ensureBN(value) {
@@ -79,6 +84,13 @@ function getTgeEscrowPDA(projectPda, programId) {
79
84
  );
80
85
  return pda;
81
86
  }
87
+ function getTokenVaultPDA(projectPda, programId) {
88
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
89
+ [Buffer.from("token_vault"), projectPda.toBuffer()],
90
+ programId
91
+ );
92
+ return pda;
93
+ }
82
94
  function getAdminConfigPDA(programId) {
83
95
  const [pda] = web3_js.PublicKey.findProgramAddressSync(
84
96
  [Buffer.from(SEEDS.ADMIN_CONFIG)],
@@ -86,6 +98,124 @@ function getAdminConfigPDA(programId) {
86
98
  );
87
99
  return pda;
88
100
  }
101
+ function getTokenomicsPDA(projectPda, programId) {
102
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
103
+ [Buffer.from("tokenomics"), projectPda.toBuffer()],
104
+ programId
105
+ );
106
+ return pda;
107
+ }
108
+ function getAllocationProposalPDA(projectPda, proposalIndex, programId) {
109
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
110
+ [
111
+ Buffer.from("allocation_proposal"),
112
+ projectPda.toBuffer(),
113
+ Buffer.from([proposalIndex])
114
+ ],
115
+ programId
116
+ );
117
+ return pda;
118
+ }
119
+ function getAllocationVotePDA(proposalPda, nftMint, programId) {
120
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
121
+ [
122
+ Buffer.from("allocation_vote"),
123
+ proposalPda.toBuffer(),
124
+ nftMint.toBuffer()
125
+ ],
126
+ programId
127
+ );
128
+ return pda;
129
+ }
130
+ function getSubAllocationVestingPDA(projectPda, subAllocationId, programId) {
131
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
132
+ [
133
+ Buffer.from("sub_allocation_vesting"),
134
+ projectPda.toBuffer(),
135
+ Buffer.from([subAllocationId])
136
+ ],
137
+ programId
138
+ );
139
+ return pda;
140
+ }
141
+ function getInvestorMilestoneVestingPDA(projectPda, milestoneIndex, investmentPda, programId) {
142
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
143
+ [
144
+ Buffer.from("investor_ms_vesting"),
145
+ projectPda.toBuffer(),
146
+ Buffer.from([milestoneIndex]),
147
+ investmentPda.toBuffer()
148
+ ],
149
+ programId
150
+ );
151
+ return pda;
152
+ }
153
+ function getFounderMilestoneVestingPDA(projectPda, milestoneIndex, programId) {
154
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
155
+ [
156
+ Buffer.from("founder_ms_vesting"),
157
+ projectPda.toBuffer(),
158
+ Buffer.from([milestoneIndex])
159
+ ],
160
+ programId
161
+ );
162
+ return pda;
163
+ }
164
+ function getFutureRoundVaultPDA(projectPda, programId) {
165
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
166
+ [Buffer.from(SEEDS.FUTURE_ROUND_STATE), projectPda.toBuffer()],
167
+ programId
168
+ );
169
+ return pda;
170
+ }
171
+ function getFundingRoundPDA(projectPda, roundNumber, programId) {
172
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
173
+ [
174
+ Buffer.from(SEEDS.FUNDING_ROUND),
175
+ projectPda.toBuffer(),
176
+ Buffer.from([roundNumber])
177
+ ],
178
+ programId
179
+ );
180
+ return pda;
181
+ }
182
+ function getRoundMilestonePDA(projectPda, roundNumber, milestoneIndex, programId) {
183
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
184
+ [
185
+ Buffer.from(SEEDS.MILESTONE),
186
+ projectPda.toBuffer(),
187
+ Buffer.from([roundNumber]),
188
+ Buffer.from([milestoneIndex])
189
+ ],
190
+ programId
191
+ );
192
+ return pda;
193
+ }
194
+ function getRoundInvestmentPDA(projectPda, roundNumber, nftMint, programId) {
195
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
196
+ [
197
+ Buffer.from(SEEDS.INVESTMENT),
198
+ projectPda.toBuffer(),
199
+ Buffer.from([roundNumber]),
200
+ nftMint.toBuffer()
201
+ ],
202
+ programId
203
+ );
204
+ return pda;
205
+ }
206
+ function getRoundInvestorMilestoneVestingPDA(projectPda, roundNumber, milestoneIndex, investmentPda, programId) {
207
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
208
+ [
209
+ Buffer.from(SEEDS.INVESTOR_MS_VESTING),
210
+ projectPda.toBuffer(),
211
+ Buffer.from([roundNumber]),
212
+ Buffer.from([milestoneIndex]),
213
+ investmentPda.toBuffer()
214
+ ],
215
+ programId
216
+ );
217
+ return pda;
218
+ }
89
219
 
90
220
  // src/accounts/index.ts
91
221
  function getAccountNamespace(program) {
@@ -233,6 +363,18 @@ async function fetchAdminConfig(program) {
233
363
  const adminConfigPda = getAdminConfigPDA(program.programId);
234
364
  return await getAccountNamespace(program).adminConfig.fetch(adminConfigPda);
235
365
  }
366
+ async function fetchTokenVault(program, projectId) {
367
+ try {
368
+ const projectPda = getProjectPDA(projectId, program.programId);
369
+ const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
370
+ return await getAccountNamespace(program).tokenVault.fetch(tokenVaultPda);
371
+ } catch (error) {
372
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
373
+ return null;
374
+ }
375
+ throw error;
376
+ }
377
+ }
236
378
  async function accountExists(program, accountType, pda) {
237
379
  try {
238
380
  await program.account[accountType].fetch(pda);
@@ -241,18 +383,404 @@ async function accountExists(program, accountType, pda) {
241
383
  return false;
242
384
  }
243
385
  }
386
+ async function fetchTokenomics(program, projectId) {
387
+ try {
388
+ const projectPda = getProjectPDA(projectId, program.programId);
389
+ const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
390
+ return await getAccountNamespace(program).tokenomics.fetch(tokenomicsPda);
391
+ } catch (error) {
392
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
393
+ return null;
394
+ }
395
+ throw error;
396
+ }
397
+ }
398
+ async function fetchAllocationProposal(program, projectId, proposalIndex) {
399
+ try {
400
+ const projectPda = getProjectPDA(projectId, program.programId);
401
+ const proposalPda = getAllocationProposalPDA(projectPda, proposalIndex, program.programId);
402
+ return await getAccountNamespace(program).allocationProposal.fetch(proposalPda);
403
+ } catch (error) {
404
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
405
+ return null;
406
+ }
407
+ throw error;
408
+ }
409
+ }
410
+ async function fetchAllAllocationProposals(program, projectId) {
411
+ const projectPda = getProjectPDA(projectId, program.programId);
412
+ const proposals = await getAccountNamespace(program).allocationProposal.all([
413
+ {
414
+ memcmp: {
415
+ offset: 8,
416
+ // Skip discriminator
417
+ bytes: projectPda.toBase58()
418
+ }
419
+ }
420
+ ]);
421
+ return proposals.map((p) => ({
422
+ publicKey: p.publicKey,
423
+ account: p.account
424
+ }));
425
+ }
426
+ async function fetchAllocationVote(program, projectId, proposalIndex, nftMint) {
427
+ try {
428
+ const projectPda = getProjectPDA(projectId, program.programId);
429
+ const proposalPda = getAllocationProposalPDA(projectPda, proposalIndex, program.programId);
430
+ const votePda = getAllocationVotePDA(proposalPda, nftMint, program.programId);
431
+ return await getAccountNamespace(program).allocationVote.fetch(votePda);
432
+ } catch (error) {
433
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
434
+ return null;
435
+ }
436
+ throw error;
437
+ }
438
+ }
439
+ async function fetchSubAllocationVesting(program, projectId, subAllocationId) {
440
+ try {
441
+ const projectPda = getProjectPDA(projectId, program.programId);
442
+ const vestingPda = getSubAllocationVestingPDA(projectPda, subAllocationId, program.programId);
443
+ return await getAccountNamespace(program).subAllocationVesting.fetch(vestingPda);
444
+ } catch (error) {
445
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
446
+ return null;
447
+ }
448
+ throw error;
449
+ }
450
+ }
451
+ async function fetchInvestorMilestoneVesting(program, projectId, milestoneIndex, nftMint) {
452
+ try {
453
+ const projectPda = getProjectPDA(projectId, program.programId);
454
+ const investmentPda = getInvestmentPDA(projectPda, nftMint, program.programId);
455
+ const vestingPda = getInvestorMilestoneVestingPDA(projectPda, milestoneIndex, investmentPda, program.programId);
456
+ return await getAccountNamespace(program).investorMilestoneVesting.fetch(vestingPda);
457
+ } catch (error) {
458
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
459
+ return null;
460
+ }
461
+ throw error;
462
+ }
463
+ }
464
+ async function fetchFounderMilestoneVesting(program, projectId, milestoneIndex) {
465
+ try {
466
+ const projectPda = getProjectPDA(projectId, program.programId);
467
+ const vestingPda = getFounderMilestoneVestingPDA(projectPda, milestoneIndex, program.programId);
468
+ return await getAccountNamespace(program).founderMilestoneVesting.fetch(vestingPda);
469
+ } catch (error) {
470
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
471
+ return null;
472
+ }
473
+ throw error;
474
+ }
475
+ }
476
+ var EARLY_TOKEN_COOLING_PERIOD_SECONDS = 86400;
477
+ var EARLY_TOKEN_COOLING_PERIOD_SECONDS_DEV = 10;
478
+ var EARLY_TOKEN_RELEASE_BPS = 500;
479
+ function canClaimEarlyTokens(investment, currentTimestamp, isDev = false) {
480
+ const now = currentTimestamp ?? Math.floor(Date.now() / 1e3);
481
+ const coolingPeriod = isDev ? EARLY_TOKEN_COOLING_PERIOD_SECONDS_DEV : EARLY_TOKEN_COOLING_PERIOD_SECONDS;
482
+ if (investment.earlyTokensClaimed) {
483
+ return { canClaim: false, reason: "Early tokens already claimed" };
484
+ }
485
+ if (investment.votingRightsActive === false) {
486
+ return { canClaim: false, reason: "Voting rights have been revoked" };
487
+ }
488
+ if (investment.withdrawnFromPivot === true) {
489
+ return { canClaim: false, reason: "Investment has been withdrawn from pivot" };
490
+ }
491
+ const investedAt = typeof investment.investedAt === "number" ? investment.investedAt : investment.investedAt.toNumber();
492
+ const coolingEndTime = investedAt + coolingPeriod;
493
+ if (now < coolingEndTime) {
494
+ const timeRemaining = coolingEndTime - now;
495
+ return {
496
+ canClaim: false,
497
+ reason: `Cooling period not expired. ${formatTimeRemaining(timeRemaining)} remaining.`,
498
+ timeRemainingSeconds: timeRemaining
499
+ };
500
+ }
501
+ return { canClaim: true };
502
+ }
503
+ function canClaimFounderEarlyTokens(project) {
504
+ if (project.founderEarlyTokensClaimed) {
505
+ return { canClaim: false, reason: "Founder early tokens already claimed" };
506
+ }
507
+ const stateStr = getProjectStateString(project.state);
508
+ const validStates = ["funded", "inProgress", "completed"];
509
+ if (!validStates.includes(stateStr)) {
510
+ return {
511
+ canClaim: false,
512
+ reason: `Project must be in Funded, InProgress, or Completed state. Current state: ${stateStr}`
513
+ };
514
+ }
515
+ return { canClaim: true };
516
+ }
517
+ function canClaimFounderMilestoneTokens(milestone) {
518
+ const stateStr = getMilestoneStateString(milestone.state);
519
+ if (stateStr !== "unlocked") {
520
+ return {
521
+ canClaim: false,
522
+ reason: `Milestone must be in Unlocked state. Current state: ${stateStr}`
523
+ };
524
+ }
525
+ return { canClaim: true };
526
+ }
527
+ function requiresBurnForRefund(project, investment) {
528
+ const isFullRefund = project.cumulativePercentage === 0;
529
+ const requiresBurn = isFullRefund && investment.earlyTokensClaimed;
530
+ if (!requiresBurn) {
531
+ return { requiresBurn: false, burnAmount: 0 };
532
+ }
533
+ const burnAmount = typeof investment.earlyTokensAmount === "number" ? investment.earlyTokensAmount : investment.earlyTokensAmount.toNumber();
534
+ return { requiresBurn: true, burnAmount };
535
+ }
536
+ function calculateEarlyTokenAmount(tokensAllocated) {
537
+ const allocated = typeof tokensAllocated === "number" ? new anchor.BN(tokensAllocated) : tokensAllocated;
538
+ return allocated.muln(EARLY_TOKEN_RELEASE_BPS).divn(1e4);
539
+ }
540
+ function calculateRemainingAllocation(tokensAllocated) {
541
+ const allocated = typeof tokensAllocated === "number" ? new anchor.BN(tokensAllocated) : tokensAllocated;
542
+ const remainingBps = 1e4 - EARLY_TOKEN_RELEASE_BPS;
543
+ return allocated.muln(remainingBps).divn(1e4);
544
+ }
545
+ function formatTimeRemaining(seconds) {
546
+ if (seconds <= 0) return "0 seconds";
547
+ const hours = Math.floor(seconds / 3600);
548
+ const minutes = Math.floor(seconds % 3600 / 60);
549
+ const secs = seconds % 60;
550
+ const parts = [];
551
+ if (hours > 0) parts.push(`${hours}h`);
552
+ if (minutes > 0) parts.push(`${minutes}m`);
553
+ if (secs > 0 && hours === 0) parts.push(`${secs}s`);
554
+ return parts.join(" ") || "0 seconds";
555
+ }
556
+ function getProjectStateString(state) {
557
+ if (typeof state === "object" && state !== null) {
558
+ const keys = Object.keys(state);
559
+ return keys[0]?.toLowerCase() ?? "unknown";
560
+ }
561
+ return "unknown";
562
+ }
563
+ function getMilestoneStateString(state) {
564
+ if (typeof state === "object" && state !== null) {
565
+ const keys = Object.keys(state);
566
+ return keys[0]?.toLowerCase() ?? "unknown";
567
+ }
568
+ return "unknown";
569
+ }
570
+ async function fetchFundingRound(program, projectId, roundNumber) {
571
+ try {
572
+ const projectPda = getProjectPDA(projectId, program.programId);
573
+ const fundingRoundPda = getFundingRoundPDA(projectPda, roundNumber, program.programId);
574
+ return await getAccountNamespace(program).fundingRound.fetch(fundingRoundPda);
575
+ } catch (error) {
576
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
577
+ return null;
578
+ }
579
+ throw error;
580
+ }
581
+ }
582
+ async function fetchAllFundingRounds(program, projectId) {
583
+ const projectPda = getProjectPDA(projectId, program.programId);
584
+ const rounds = await getAccountNamespace(program).fundingRound.all([
585
+ {
586
+ memcmp: {
587
+ offset: 8,
588
+ // Skip discriminator
589
+ bytes: projectPda.toBase58()
590
+ }
591
+ }
592
+ ]);
593
+ return rounds.map((r) => ({
594
+ publicKey: r.publicKey,
595
+ account: r.account
596
+ }));
597
+ }
598
+ async function fetchRoundMilestone(program, projectId, roundNumber, milestoneIndex) {
599
+ try {
600
+ const projectPda = getProjectPDA(projectId, program.programId);
601
+ const milestonePda = getRoundMilestonePDA(projectPda, roundNumber, milestoneIndex, program.programId);
602
+ return await getAccountNamespace(program).milestone.fetch(milestonePda);
603
+ } catch (error) {
604
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
605
+ return null;
606
+ }
607
+ throw error;
608
+ }
609
+ }
610
+ async function fetchRoundInvestment(program, projectId, roundNumber, nftMint) {
611
+ try {
612
+ const projectPda = getProjectPDA(projectId, program.programId);
613
+ const investmentPda = getRoundInvestmentPDA(projectPda, roundNumber, nftMint, program.programId);
614
+ return await getAccountNamespace(program).investment.fetch(investmentPda);
615
+ } catch (error) {
616
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
617
+ return null;
618
+ }
619
+ throw error;
620
+ }
621
+ }
622
+ async function fetchRoundInvestorMilestoneVesting(program, projectId, roundNumber, milestoneIndex, nftMint) {
623
+ try {
624
+ const projectPda = getProjectPDA(projectId, program.programId);
625
+ const investmentPda = getRoundInvestmentPDA(projectPda, roundNumber, nftMint, program.programId);
626
+ const vestingPda = getRoundInvestorMilestoneVestingPDA(
627
+ projectPda,
628
+ roundNumber,
629
+ milestoneIndex,
630
+ investmentPda,
631
+ program.programId
632
+ );
633
+ return await getAccountNamespace(program).investorMilestoneVesting.fetch(vestingPda);
634
+ } catch (error) {
635
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
636
+ return null;
637
+ }
638
+ throw error;
639
+ }
640
+ }
641
+ async function fetchFutureRoundVault(program, projectId) {
642
+ try {
643
+ const projectPda = getProjectPDA(projectId, program.programId);
644
+ const vaultPda = getFutureRoundVaultPDA(projectPda, program.programId);
645
+ return await getAccountNamespace(program).futureRoundVault.fetch(vaultPda);
646
+ } catch (error) {
647
+ if (error instanceof Error && error.message?.includes("Account does not exist")) {
648
+ return null;
649
+ }
650
+ throw error;
651
+ }
652
+ }
653
+ function canClaimRoundEarlyTokens(investment, currentTimestamp, isDev = false) {
654
+ if (investment.roundNumber < 2) {
655
+ return { canClaim: false, reason: "R1 investments use claim_investor_early_tokens instruction" };
656
+ }
657
+ return canClaimEarlyTokens(investment, currentTimestamp, isDev);
658
+ }
659
+ function isR1FullyFunded(project) {
660
+ const raised = typeof project.totalRaised === "number" ? new anchor.BN(project.totalRaised) : project.totalRaised;
661
+ const goal = typeof project.fundingGoal === "number" ? new anchor.BN(project.fundingGoal) : project.fundingGoal;
662
+ return raised.gte(goal);
663
+ }
664
+ function isFundingRoundFullyFunded(fundingRound) {
665
+ const stateStr = getRoundStateString(fundingRound.state);
666
+ return ["funded", "inProgress", "inprogress", "completed"].includes(stateStr);
667
+ }
668
+ async function isRoundFullyFunded(program, projectId, roundNumber) {
669
+ if (roundNumber === 1) {
670
+ const project = await fetchProject(program, projectId);
671
+ if (!project) return false;
672
+ return isR1FullyFunded(project);
673
+ } else {
674
+ const fundingRound = await fetchFundingRound(program, projectId, roundNumber);
675
+ if (!fundingRound) return false;
676
+ return isFundingRoundFullyFunded(fundingRound);
677
+ }
678
+ }
679
+ async function canOpenNextRound(program, projectId) {
680
+ const project = await fetchProject(program, projectId);
681
+ if (!project) {
682
+ return { canOpen: false, reason: "Project not found" };
683
+ }
684
+ const projectState = getProjectStateString(project.state);
685
+ if (!["inProgress", "inprogress", "completed"].includes(projectState)) {
686
+ return {
687
+ canOpen: false,
688
+ reason: `Project must be in InProgress or Completed state. Current: ${projectState}`
689
+ };
690
+ }
691
+ if (projectState !== "completed" && project.milestonesPassed === 0) {
692
+ return {
693
+ canOpen: false,
694
+ reason: "At least one milestone must pass before opening next round"
695
+ };
696
+ }
697
+ if (project.activeRound !== 0) {
698
+ return {
699
+ canOpen: false,
700
+ reason: `Round ${project.activeRound} is already active`
701
+ };
702
+ }
703
+ const currentRound = project.roundCount;
704
+ const isCurrentFunded = await isRoundFullyFunded(program, projectId, currentRound);
705
+ if (!isCurrentFunded) {
706
+ return {
707
+ canOpen: false,
708
+ reason: `Current round ${currentRound} must be fully funded before opening next round`
709
+ };
710
+ }
711
+ const tokenomics = await fetchTokenomics(program, projectId);
712
+ if (!tokenomics) {
713
+ return { canOpen: false, reason: "Tokenomics not found" };
714
+ }
715
+ if (tokenomics.futureRoundAllocationBps === 0) {
716
+ return {
717
+ canOpen: false,
718
+ reason: "No future round allocation configured"
719
+ };
720
+ }
721
+ const remainingAllocation = tokenomics.futureRoundAllocationBps - (tokenomics.usedFutureRoundBps || 0);
722
+ if (remainingAllocation <= 0) {
723
+ return {
724
+ canOpen: false,
725
+ reason: "Future round allocation pool exhausted"
726
+ };
727
+ }
728
+ return {
729
+ canOpen: true,
730
+ nextRoundNumber: currentRound + 1
731
+ };
732
+ }
733
+ function getRemainingFutureRoundAllocation(tokenomics) {
734
+ return tokenomics.futureRoundAllocationBps - (tokenomics.usedFutureRoundBps || 0);
735
+ }
736
+ function getRoundStateString(state) {
737
+ if (typeof state === "object" && state !== null) {
738
+ const keys = Object.keys(state);
739
+ return keys[0]?.toLowerCase() ?? "unknown";
740
+ }
741
+ return "unknown";
742
+ }
244
743
 
744
+ exports.EARLY_TOKEN_COOLING_PERIOD_SECONDS = EARLY_TOKEN_COOLING_PERIOD_SECONDS;
745
+ exports.EARLY_TOKEN_COOLING_PERIOD_SECONDS_DEV = EARLY_TOKEN_COOLING_PERIOD_SECONDS_DEV;
746
+ exports.EARLY_TOKEN_RELEASE_BPS = EARLY_TOKEN_RELEASE_BPS;
245
747
  exports.accountExists = accountExists;
748
+ exports.calculateEarlyTokenAmount = calculateEarlyTokenAmount;
749
+ exports.calculateRemainingAllocation = calculateRemainingAllocation;
750
+ exports.canClaimEarlyTokens = canClaimEarlyTokens;
751
+ exports.canClaimFounderEarlyTokens = canClaimFounderEarlyTokens;
752
+ exports.canClaimFounderMilestoneTokens = canClaimFounderMilestoneTokens;
753
+ exports.canClaimRoundEarlyTokens = canClaimRoundEarlyTokens;
754
+ exports.canOpenNextRound = canOpenNextRound;
246
755
  exports.fetchAdminConfig = fetchAdminConfig;
756
+ exports.fetchAllAllocationProposals = fetchAllAllocationProposals;
757
+ exports.fetchAllFundingRounds = fetchAllFundingRounds;
247
758
  exports.fetchAllInvestments = fetchAllInvestments;
248
759
  exports.fetchAllMilestones = fetchAllMilestones;
249
760
  exports.fetchAllVotes = fetchAllVotes;
761
+ exports.fetchAllocationProposal = fetchAllocationProposal;
762
+ exports.fetchAllocationVote = fetchAllocationVote;
763
+ exports.fetchFounderMilestoneVesting = fetchFounderMilestoneVesting;
764
+ exports.fetchFundingRound = fetchFundingRound;
765
+ exports.fetchFutureRoundVault = fetchFutureRoundVault;
250
766
  exports.fetchInvestment = fetchInvestment;
767
+ exports.fetchInvestorMilestoneVesting = fetchInvestorMilestoneVesting;
251
768
  exports.fetchMilestone = fetchMilestone;
252
769
  exports.fetchPivotProposal = fetchPivotProposal;
253
770
  exports.fetchProject = fetchProject;
254
771
  exports.fetchProjectByPda = fetchProjectByPda;
772
+ exports.fetchRoundInvestment = fetchRoundInvestment;
773
+ exports.fetchRoundInvestorMilestoneVesting = fetchRoundInvestorMilestoneVesting;
774
+ exports.fetchRoundMilestone = fetchRoundMilestone;
775
+ exports.fetchSubAllocationVesting = fetchSubAllocationVesting;
255
776
  exports.fetchTgeEscrow = fetchTgeEscrow;
777
+ exports.fetchTokenVault = fetchTokenVault;
778
+ exports.fetchTokenomics = fetchTokenomics;
256
779
  exports.fetchVote = fetchVote;
780
+ exports.getRemainingFutureRoundAllocation = getRemainingFutureRoundAllocation;
781
+ exports.isFundingRoundFullyFunded = isFundingRoundFullyFunded;
782
+ exports.isR1FullyFunded = isR1FullyFunded;
783
+ exports.isRoundFullyFunded = isRoundFullyFunded;
784
+ exports.requiresBurnForRefund = requiresBurnForRefund;
257
785
  //# sourceMappingURL=index.cjs.map
258
786
  //# sourceMappingURL=index.cjs.map