@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.
- package/README.md +11 -9
- package/dist/accounts/index.cjs +531 -3
- package/dist/accounts/index.cjs.map +1 -1
- package/dist/accounts/index.d.cts +307 -2
- package/dist/accounts/index.d.ts +307 -2
- package/dist/accounts/index.js +503 -4
- package/dist/accounts/index.js.map +1 -1
- package/dist/constants/index.cjs +41 -3
- package/dist/constants/index.cjs.map +1 -1
- package/dist/constants/index.d.cts +38 -3
- package/dist/constants/index.d.ts +38 -3
- package/dist/constants/index.js +40 -4
- package/dist/constants/index.js.map +1 -1
- package/dist/index.cjs +2297 -361
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +566 -7
- package/dist/index.d.ts +566 -7
- package/dist/index.js +2279 -379
- package/dist/index.js.map +1 -1
- package/dist/instructions/index.cjs +783 -40
- package/dist/instructions/index.cjs.map +1 -1
- package/dist/instructions/index.d.cts +492 -6
- package/dist/instructions/index.d.ts +492 -6
- package/dist/instructions/index.js +762 -42
- package/dist/instructions/index.js.map +1 -1
- package/dist/pdas/index.cjs +163 -1
- package/dist/pdas/index.cjs.map +1 -1
- package/dist/pdas/index.d.cts +131 -1
- package/dist/pdas/index.d.ts +131 -1
- package/dist/pdas/index.js +151 -2
- package/dist/pdas/index.js.map +1 -1
- package/dist/types/index.cjs +9 -0
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +586 -3
- package/dist/types/index.d.ts +586 -3
- package/dist/types/index.js +9 -1
- package/dist/types/index.js.map +1 -1
- package/package.json +5 -3
- package/src/__tests__/dynamic-tokenomics.test.ts +358 -0
- package/src/accounts/index.ts +852 -1
- package/src/client.ts +1130 -1
- package/src/constants/index.ts +48 -2
- package/src/index.ts +58 -0
- package/src/instructions/index.ts +1383 -40
- package/src/pdas/index.ts +346 -0
- package/src/types/index.ts +698 -2
- package/src/utils/index.ts +90 -0
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { PublicKey, SystemProgram, SYSVAR_INSTRUCTIONS_PUBKEY, SYSVAR_RENT_PUBKEY, ComputeBudgetProgram, SYSVAR_CLOCK_PUBKEY } from '@solana/web3.js';
|
|
2
|
-
export { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
3
1
|
import { BN, AnchorError } from '@coral-xyz/anchor';
|
|
4
2
|
export { BN } from '@coral-xyz/anchor';
|
|
3
|
+
import { PublicKey, ComputeBudgetProgram, SystemProgram, SYSVAR_INSTRUCTIONS_PUBKEY, SYSVAR_RENT_PUBKEY, SYSVAR_CLOCK_PUBKEY } from '@solana/web3.js';
|
|
4
|
+
export { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
5
5
|
import { getAssociatedTokenAddressSync, TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
6
6
|
|
|
7
|
-
// src/
|
|
7
|
+
// src/client.ts
|
|
8
8
|
|
|
9
9
|
// src/constants/index.ts
|
|
10
10
|
var SEEDS = {
|
|
@@ -20,7 +20,13 @@ var SEEDS = {
|
|
|
20
20
|
SCAM_REPORT: "scam_report",
|
|
21
21
|
ADMIN_CONFIG: "admin-config",
|
|
22
22
|
NFT_MINT: "nft_mint",
|
|
23
|
-
AUTHORITY: "authority"
|
|
23
|
+
AUTHORITY: "authority",
|
|
24
|
+
FUTURE_ROUND_VAULT: "future_round_vault",
|
|
25
|
+
FUTURE_ROUND_STATE: "future_round_state",
|
|
26
|
+
// Multi-Round Fundraising seeds
|
|
27
|
+
FUNDING_ROUND: "funding_round",
|
|
28
|
+
ROUND_ESCROW: "round_escrow",
|
|
29
|
+
INVESTOR_MS_VESTING: "investor_ms_vesting"
|
|
24
30
|
};
|
|
25
31
|
var VALIDATION = {
|
|
26
32
|
/** Minimum number of milestones per project */
|
|
@@ -146,9 +152,9 @@ var GOVERNANCE = {
|
|
|
146
152
|
};
|
|
147
153
|
var NFT = {
|
|
148
154
|
/** NFT symbol */
|
|
149
|
-
SYMBOL: "
|
|
155
|
+
SYMBOL: "ZRI",
|
|
150
156
|
/** NFT name prefix */
|
|
151
|
-
NAME_PREFIX: "Raise Investment #",
|
|
157
|
+
NAME_PREFIX: "Zemyth Raise Investment #",
|
|
152
158
|
/** Royalty basis points (2%) */
|
|
153
159
|
ROYALTY_BASIS_POINTS: 200
|
|
154
160
|
};
|
|
@@ -160,6 +166,26 @@ var USDC = {
|
|
|
160
166
|
/** Convert lamports to USDC */
|
|
161
167
|
fromAmount: (lamports) => Number(lamports) / 10 ** 6
|
|
162
168
|
};
|
|
169
|
+
var TOKENOMICS = {
|
|
170
|
+
/** Minimum investor allocation (20%) */
|
|
171
|
+
MIN_INVESTOR_ALLOCATION_BPS: 2e3,
|
|
172
|
+
/** Minimum founder allocation (5%) if > 0 */
|
|
173
|
+
MIN_FOUNDER_ALLOCATION_BPS: 500,
|
|
174
|
+
/** Minimum LP token allocation (5%) */
|
|
175
|
+
MIN_LP_TOKEN_ALLOCATION_BPS: 500,
|
|
176
|
+
/** Minimum LP USDC allocation (5%) */
|
|
177
|
+
MIN_LP_USDC_BPS: 500,
|
|
178
|
+
/** Minimum Zemyth allocation (1%) */
|
|
179
|
+
MIN_ZEMYTH_ALLOCATION_BPS: 100,
|
|
180
|
+
/** Default Zemyth allocation (1%) */
|
|
181
|
+
DEFAULT_ZEMYTH_ALLOCATION_BPS: 100,
|
|
182
|
+
/** Minimum future round allocation (10%) if > 0 */
|
|
183
|
+
MIN_FUTURE_ROUND_ALLOCATION_BPS: 1e3,
|
|
184
|
+
/** Maximum token symbol length */
|
|
185
|
+
MAX_TOKEN_SYMBOL_LEN: 8,
|
|
186
|
+
/** Total allocation must sum to this (100% = 10000 bps) */
|
|
187
|
+
TOTAL_ALLOCATION_BPS: 1e4
|
|
188
|
+
};
|
|
163
189
|
|
|
164
190
|
// src/pdas/index.ts
|
|
165
191
|
function ensureBN(value) {
|
|
@@ -353,8 +379,149 @@ function getFounderVestingPDA(projectPda, programId) {
|
|
|
353
379
|
);
|
|
354
380
|
return pda;
|
|
355
381
|
}
|
|
356
|
-
|
|
357
|
-
|
|
382
|
+
function getAllocationProposalPDA(projectPda, proposalIndex, programId) {
|
|
383
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
384
|
+
[
|
|
385
|
+
Buffer.from("allocation_proposal"),
|
|
386
|
+
projectPda.toBuffer(),
|
|
387
|
+
Buffer.from([proposalIndex])
|
|
388
|
+
],
|
|
389
|
+
programId
|
|
390
|
+
);
|
|
391
|
+
return pda;
|
|
392
|
+
}
|
|
393
|
+
function getAllocationVotePDA(proposalPda, nftMint, programId) {
|
|
394
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
395
|
+
[
|
|
396
|
+
Buffer.from("allocation_vote"),
|
|
397
|
+
proposalPda.toBuffer(),
|
|
398
|
+
nftMint.toBuffer()
|
|
399
|
+
],
|
|
400
|
+
programId
|
|
401
|
+
);
|
|
402
|
+
return pda;
|
|
403
|
+
}
|
|
404
|
+
function getSubAllocationVestingPDA(projectPda, subAllocationId, programId) {
|
|
405
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
406
|
+
[
|
|
407
|
+
Buffer.from("sub_allocation_vesting"),
|
|
408
|
+
projectPda.toBuffer(),
|
|
409
|
+
Buffer.from([subAllocationId])
|
|
410
|
+
],
|
|
411
|
+
programId
|
|
412
|
+
);
|
|
413
|
+
return pda;
|
|
414
|
+
}
|
|
415
|
+
function getInvestorMilestoneVestingPDA(projectPda, milestoneIndex, investmentPda, programId) {
|
|
416
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
417
|
+
[
|
|
418
|
+
Buffer.from("investor_ms_vesting"),
|
|
419
|
+
projectPda.toBuffer(),
|
|
420
|
+
Buffer.from([milestoneIndex]),
|
|
421
|
+
investmentPda.toBuffer()
|
|
422
|
+
],
|
|
423
|
+
programId
|
|
424
|
+
);
|
|
425
|
+
return pda;
|
|
426
|
+
}
|
|
427
|
+
function getFounderMilestoneVestingPDA(projectPda, milestoneIndex, programId) {
|
|
428
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
429
|
+
[
|
|
430
|
+
Buffer.from("founder_ms_vesting"),
|
|
431
|
+
projectPda.toBuffer(),
|
|
432
|
+
Buffer.from([milestoneIndex])
|
|
433
|
+
],
|
|
434
|
+
programId
|
|
435
|
+
);
|
|
436
|
+
return pda;
|
|
437
|
+
}
|
|
438
|
+
function getFutureRoundTokenVaultPDA(projectPda, programId) {
|
|
439
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
440
|
+
[Buffer.from(SEEDS.FUTURE_ROUND_VAULT), projectPda.toBuffer()],
|
|
441
|
+
programId
|
|
442
|
+
);
|
|
443
|
+
return pda;
|
|
444
|
+
}
|
|
445
|
+
function getFutureRoundVaultPDA(projectPda, programId) {
|
|
446
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
447
|
+
[Buffer.from(SEEDS.FUTURE_ROUND_STATE), projectPda.toBuffer()],
|
|
448
|
+
programId
|
|
449
|
+
);
|
|
450
|
+
return pda;
|
|
451
|
+
}
|
|
452
|
+
function getFundingRoundPDA(projectPda, roundNumber, programId) {
|
|
453
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
454
|
+
[
|
|
455
|
+
Buffer.from(SEEDS.FUNDING_ROUND),
|
|
456
|
+
projectPda.toBuffer(),
|
|
457
|
+
Buffer.from([roundNumber])
|
|
458
|
+
],
|
|
459
|
+
programId
|
|
460
|
+
);
|
|
461
|
+
return pda;
|
|
462
|
+
}
|
|
463
|
+
function getRoundEscrowPDA(projectPda, roundNumber, programId) {
|
|
464
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
465
|
+
[
|
|
466
|
+
Buffer.from(SEEDS.ROUND_ESCROW),
|
|
467
|
+
projectPda.toBuffer(),
|
|
468
|
+
Buffer.from([roundNumber])
|
|
469
|
+
],
|
|
470
|
+
programId
|
|
471
|
+
);
|
|
472
|
+
return pda;
|
|
473
|
+
}
|
|
474
|
+
function getRoundMilestonePDA(projectPda, roundNumber, milestoneIndex, programId) {
|
|
475
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
476
|
+
[
|
|
477
|
+
Buffer.from(SEEDS.MILESTONE),
|
|
478
|
+
projectPda.toBuffer(),
|
|
479
|
+
Buffer.from([roundNumber]),
|
|
480
|
+
Buffer.from([milestoneIndex])
|
|
481
|
+
],
|
|
482
|
+
programId
|
|
483
|
+
);
|
|
484
|
+
return pda;
|
|
485
|
+
}
|
|
486
|
+
function getRoundNftMintPDA(projectId, roundNumber, investor, investmentCount, programId) {
|
|
487
|
+
const projectIdBN = ensureBN(projectId);
|
|
488
|
+
const countBN = ensureBN(investmentCount);
|
|
489
|
+
return PublicKey.findProgramAddressSync(
|
|
490
|
+
[
|
|
491
|
+
Buffer.from(SEEDS.NFT_MINT),
|
|
492
|
+
projectIdBN.toArrayLike(Buffer, "le", 8),
|
|
493
|
+
Buffer.from([roundNumber]),
|
|
494
|
+
investor.toBuffer(),
|
|
495
|
+
countBN.toArrayLike(Buffer, "le", 8)
|
|
496
|
+
],
|
|
497
|
+
programId
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
function getRoundInvestmentPDA(projectPda, roundNumber, nftMint, programId) {
|
|
501
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
502
|
+
[
|
|
503
|
+
Buffer.from(SEEDS.INVESTMENT),
|
|
504
|
+
projectPda.toBuffer(),
|
|
505
|
+
Buffer.from([roundNumber]),
|
|
506
|
+
nftMint.toBuffer()
|
|
507
|
+
],
|
|
508
|
+
programId
|
|
509
|
+
);
|
|
510
|
+
return pda;
|
|
511
|
+
}
|
|
512
|
+
function getRoundInvestorMilestoneVestingPDA(projectPda, roundNumber, milestoneIndex, investmentPda, programId) {
|
|
513
|
+
const [pda] = PublicKey.findProgramAddressSync(
|
|
514
|
+
[
|
|
515
|
+
Buffer.from(SEEDS.INVESTOR_MS_VESTING),
|
|
516
|
+
projectPda.toBuffer(),
|
|
517
|
+
Buffer.from([roundNumber]),
|
|
518
|
+
Buffer.from([milestoneIndex]),
|
|
519
|
+
investmentPda.toBuffer()
|
|
520
|
+
],
|
|
521
|
+
programId
|
|
522
|
+
);
|
|
523
|
+
return pda;
|
|
524
|
+
}
|
|
358
525
|
function getAccountNamespace(program) {
|
|
359
526
|
return program.account;
|
|
360
527
|
}
|
|
@@ -500,6 +667,18 @@ async function fetchAdminConfig(program) {
|
|
|
500
667
|
const adminConfigPda = getAdminConfigPDA(program.programId);
|
|
501
668
|
return await getAccountNamespace(program).adminConfig.fetch(adminConfigPda);
|
|
502
669
|
}
|
|
670
|
+
async function fetchTokenVault(program, projectId) {
|
|
671
|
+
try {
|
|
672
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
673
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
674
|
+
return await getAccountNamespace(program).tokenVault.fetch(tokenVaultPda);
|
|
675
|
+
} catch (error) {
|
|
676
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
677
|
+
return null;
|
|
678
|
+
}
|
|
679
|
+
throw error;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
503
682
|
async function accountExists(program, accountType, pda) {
|
|
504
683
|
try {
|
|
505
684
|
await program.account[accountType].fetch(pda);
|
|
@@ -508,107 +687,468 @@ async function accountExists(program, accountType, pda) {
|
|
|
508
687
|
return false;
|
|
509
688
|
}
|
|
510
689
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
690
|
+
async function fetchTokenomics(program, projectId) {
|
|
691
|
+
try {
|
|
692
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
693
|
+
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
694
|
+
return await getAccountNamespace(program).tokenomics.fetch(tokenomicsPda);
|
|
695
|
+
} catch (error) {
|
|
696
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
697
|
+
return null;
|
|
698
|
+
}
|
|
699
|
+
throw error;
|
|
515
700
|
}
|
|
516
|
-
return new PublicKey(String(value));
|
|
517
|
-
}
|
|
518
|
-
function getMethods(program) {
|
|
519
|
-
return program.methods;
|
|
520
701
|
}
|
|
521
|
-
function
|
|
522
|
-
|
|
702
|
+
async function fetchAllocationProposal(program, projectId, proposalIndex) {
|
|
703
|
+
try {
|
|
704
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
705
|
+
const proposalPda = getAllocationProposalPDA(projectPda, proposalIndex, program.programId);
|
|
706
|
+
return await getAccountNamespace(program).allocationProposal.fetch(proposalPda);
|
|
707
|
+
} catch (error) {
|
|
708
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
throw error;
|
|
712
|
+
}
|
|
523
713
|
}
|
|
524
|
-
async function
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
714
|
+
async function fetchAllAllocationProposals(program, projectId) {
|
|
715
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
716
|
+
const proposals = await getAccountNamespace(program).allocationProposal.all([
|
|
717
|
+
{
|
|
718
|
+
memcmp: {
|
|
719
|
+
offset: 8,
|
|
720
|
+
// Skip discriminator
|
|
721
|
+
bytes: projectPda.toBase58()
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
]);
|
|
725
|
+
return proposals.map((p) => ({
|
|
726
|
+
publicKey: p.publicKey,
|
|
727
|
+
account: p.account
|
|
728
|
+
}));
|
|
529
729
|
}
|
|
530
|
-
async function
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
730
|
+
async function fetchAllocationVote(program, projectId, proposalIndex, nftMint) {
|
|
731
|
+
try {
|
|
732
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
733
|
+
const proposalPda = getAllocationProposalPDA(projectPda, proposalIndex, program.programId);
|
|
734
|
+
const votePda = getAllocationVotePDA(proposalPda, nftMint, program.programId);
|
|
735
|
+
return await getAccountNamespace(program).allocationVote.fetch(votePda);
|
|
736
|
+
} catch (error) {
|
|
737
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
738
|
+
return null;
|
|
739
|
+
}
|
|
740
|
+
throw error;
|
|
741
|
+
}
|
|
535
742
|
}
|
|
536
|
-
async function
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
743
|
+
async function fetchSubAllocationVesting(program, projectId, subAllocationId) {
|
|
744
|
+
try {
|
|
745
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
746
|
+
const vestingPda = getSubAllocationVestingPDA(projectPda, subAllocationId, program.programId);
|
|
747
|
+
return await getAccountNamespace(program).subAllocationVesting.fetch(vestingPda);
|
|
748
|
+
} catch (error) {
|
|
749
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
750
|
+
return null;
|
|
751
|
+
}
|
|
752
|
+
throw error;
|
|
753
|
+
}
|
|
540
754
|
}
|
|
541
|
-
function
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
755
|
+
async function fetchInvestorMilestoneVesting(program, projectId, milestoneIndex, nftMint) {
|
|
756
|
+
try {
|
|
757
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
758
|
+
const investmentPda = getInvestmentPDA(projectPda, nftMint, program.programId);
|
|
759
|
+
const vestingPda = getInvestorMilestoneVestingPDA(projectPda, milestoneIndex, investmentPda, program.programId);
|
|
760
|
+
return await getAccountNamespace(program).investorMilestoneVesting.fetch(vestingPda);
|
|
761
|
+
} catch (error) {
|
|
762
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
763
|
+
return null;
|
|
764
|
+
}
|
|
765
|
+
throw error;
|
|
546
766
|
}
|
|
547
|
-
return bytes;
|
|
548
767
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
768
|
+
async function fetchFounderMilestoneVesting(program, projectId, milestoneIndex) {
|
|
769
|
+
try {
|
|
770
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
771
|
+
const vestingPda = getFounderMilestoneVestingPDA(projectPda, milestoneIndex, program.programId);
|
|
772
|
+
return await getAccountNamespace(program).founderMilestoneVesting.fetch(vestingPda);
|
|
773
|
+
} catch (error) {
|
|
774
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
throw error;
|
|
778
|
+
}
|
|
559
779
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
780
|
+
var EARLY_TOKEN_COOLING_PERIOD_SECONDS = 86400;
|
|
781
|
+
var EARLY_TOKEN_COOLING_PERIOD_SECONDS_DEV = 10;
|
|
782
|
+
var EARLY_TOKEN_RELEASE_BPS = 500;
|
|
783
|
+
function canClaimEarlyTokens(investment, currentTimestamp, isDev = false) {
|
|
784
|
+
const now = currentTimestamp ?? Math.floor(Date.now() / 1e3);
|
|
785
|
+
const coolingPeriod = isDev ? EARLY_TOKEN_COOLING_PERIOD_SECONDS_DEV : EARLY_TOKEN_COOLING_PERIOD_SECONDS;
|
|
786
|
+
if (investment.earlyTokensClaimed) {
|
|
787
|
+
return { canClaim: false, reason: "Early tokens already claimed" };
|
|
788
|
+
}
|
|
789
|
+
if (investment.votingRightsActive === false) {
|
|
790
|
+
return { canClaim: false, reason: "Voting rights have been revoked" };
|
|
791
|
+
}
|
|
792
|
+
if (investment.withdrawnFromPivot === true) {
|
|
793
|
+
return { canClaim: false, reason: "Investment has been withdrawn from pivot" };
|
|
794
|
+
}
|
|
795
|
+
const investedAt = typeof investment.investedAt === "number" ? investment.investedAt : investment.investedAt.toNumber();
|
|
796
|
+
const coolingEndTime = investedAt + coolingPeriod;
|
|
797
|
+
if (now < coolingEndTime) {
|
|
798
|
+
const timeRemaining2 = coolingEndTime - now;
|
|
799
|
+
return {
|
|
800
|
+
canClaim: false,
|
|
801
|
+
reason: `Cooling period not expired. ${formatTimeRemaining(timeRemaining2)} remaining.`,
|
|
802
|
+
timeRemainingSeconds: timeRemaining2
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
return { canClaim: true };
|
|
564
806
|
}
|
|
565
|
-
function
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
const
|
|
570
|
-
const
|
|
571
|
-
if (
|
|
572
|
-
const minDays = isDev ? "60 seconds" : "7 days";
|
|
807
|
+
function canClaimFounderEarlyTokens(project) {
|
|
808
|
+
if (project.founderEarlyTokensClaimed) {
|
|
809
|
+
return { canClaim: false, reason: "Founder early tokens already claimed" };
|
|
810
|
+
}
|
|
811
|
+
const stateStr = getProjectStateString(project.state);
|
|
812
|
+
const validStates = ["funded", "inProgress", "completed"];
|
|
813
|
+
if (!validStates.includes(stateStr)) {
|
|
573
814
|
return {
|
|
574
|
-
|
|
575
|
-
|
|
815
|
+
canClaim: false,
|
|
816
|
+
reason: `Project must be in Funded, InProgress, or Completed state. Current state: ${stateStr}`
|
|
576
817
|
};
|
|
577
818
|
}
|
|
578
|
-
|
|
819
|
+
return { canClaim: true };
|
|
820
|
+
}
|
|
821
|
+
function canClaimFounderMilestoneTokens(milestone) {
|
|
822
|
+
const stateStr = getMilestoneStateString(milestone.state);
|
|
823
|
+
if (stateStr !== "unlocked") {
|
|
579
824
|
return {
|
|
580
|
-
|
|
581
|
-
|
|
825
|
+
canClaim: false,
|
|
826
|
+
reason: `Milestone must be in Unlocked state. Current state: ${stateStr}`
|
|
582
827
|
};
|
|
583
828
|
}
|
|
584
|
-
return {
|
|
829
|
+
return { canClaim: true };
|
|
585
830
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
831
|
+
function requiresBurnForRefund(project, investment) {
|
|
832
|
+
const isFullRefund = project.cumulativePercentage === 0;
|
|
833
|
+
const requiresBurn = isFullRefund && investment.earlyTokensClaimed;
|
|
834
|
+
if (!requiresBurn) {
|
|
835
|
+
return { requiresBurn: false, burnAmount: 0 };
|
|
836
|
+
}
|
|
837
|
+
const burnAmount = typeof investment.earlyTokensAmount === "number" ? investment.earlyTokensAmount : investment.earlyTokensAmount.toNumber();
|
|
838
|
+
return { requiresBurn: true, burnAmount };
|
|
839
|
+
}
|
|
840
|
+
function calculateEarlyTokenAmount(tokensAllocated) {
|
|
841
|
+
const allocated = typeof tokensAllocated === "number" ? new BN(tokensAllocated) : tokensAllocated;
|
|
842
|
+
return allocated.muln(EARLY_TOKEN_RELEASE_BPS).divn(1e4);
|
|
843
|
+
}
|
|
844
|
+
function calculateRemainingAllocation(tokensAllocated) {
|
|
845
|
+
const allocated = typeof tokensAllocated === "number" ? new BN(tokensAllocated) : tokensAllocated;
|
|
846
|
+
const remainingBps = 1e4 - EARLY_TOKEN_RELEASE_BPS;
|
|
847
|
+
return allocated.muln(remainingBps).divn(1e4);
|
|
848
|
+
}
|
|
849
|
+
function formatTimeRemaining(seconds) {
|
|
850
|
+
if (seconds <= 0) return "0 seconds";
|
|
851
|
+
const hours = Math.floor(seconds / 3600);
|
|
852
|
+
const minutes = Math.floor(seconds % 3600 / 60);
|
|
853
|
+
const secs = seconds % 60;
|
|
854
|
+
const parts = [];
|
|
855
|
+
if (hours > 0) parts.push(`${hours}h`);
|
|
856
|
+
if (minutes > 0) parts.push(`${minutes}m`);
|
|
857
|
+
if (secs > 0 && hours === 0) parts.push(`${secs}s`);
|
|
858
|
+
return parts.join(" ") || "0 seconds";
|
|
859
|
+
}
|
|
860
|
+
function getProjectStateString(state) {
|
|
861
|
+
if (typeof state === "object" && state !== null) {
|
|
862
|
+
const keys = Object.keys(state);
|
|
863
|
+
return keys[0]?.toLowerCase() ?? "unknown";
|
|
864
|
+
}
|
|
865
|
+
return "unknown";
|
|
866
|
+
}
|
|
867
|
+
function getMilestoneStateString(state) {
|
|
868
|
+
if (typeof state === "object" && state !== null) {
|
|
869
|
+
const keys = Object.keys(state);
|
|
870
|
+
return keys[0]?.toLowerCase() ?? "unknown";
|
|
871
|
+
}
|
|
872
|
+
return "unknown";
|
|
873
|
+
}
|
|
874
|
+
async function fetchFundingRound(program, projectId, roundNumber) {
|
|
875
|
+
try {
|
|
876
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
877
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, roundNumber, program.programId);
|
|
878
|
+
return await getAccountNamespace(program).fundingRound.fetch(fundingRoundPda);
|
|
879
|
+
} catch (error) {
|
|
880
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
881
|
+
return null;
|
|
882
|
+
}
|
|
883
|
+
throw error;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
async function fetchAllFundingRounds(program, projectId) {
|
|
887
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
888
|
+
const rounds = await getAccountNamespace(program).fundingRound.all([
|
|
889
|
+
{
|
|
890
|
+
memcmp: {
|
|
891
|
+
offset: 8,
|
|
892
|
+
// Skip discriminator
|
|
893
|
+
bytes: projectPda.toBase58()
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
]);
|
|
897
|
+
return rounds.map((r) => ({
|
|
898
|
+
publicKey: r.publicKey,
|
|
899
|
+
account: r.account
|
|
900
|
+
}));
|
|
901
|
+
}
|
|
902
|
+
async function fetchRoundMilestone(program, projectId, roundNumber, milestoneIndex) {
|
|
903
|
+
try {
|
|
904
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
905
|
+
const milestonePda = getRoundMilestonePDA(projectPda, roundNumber, milestoneIndex, program.programId);
|
|
906
|
+
return await getAccountNamespace(program).milestone.fetch(milestonePda);
|
|
907
|
+
} catch (error) {
|
|
908
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
909
|
+
return null;
|
|
910
|
+
}
|
|
911
|
+
throw error;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
async function fetchRoundInvestment(program, projectId, roundNumber, nftMint) {
|
|
915
|
+
try {
|
|
916
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
917
|
+
const investmentPda = getRoundInvestmentPDA(projectPda, roundNumber, nftMint, program.programId);
|
|
918
|
+
return await getAccountNamespace(program).investment.fetch(investmentPda);
|
|
919
|
+
} catch (error) {
|
|
920
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
921
|
+
return null;
|
|
922
|
+
}
|
|
923
|
+
throw error;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
async function fetchRoundInvestorMilestoneVesting(program, projectId, roundNumber, milestoneIndex, nftMint) {
|
|
927
|
+
try {
|
|
928
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
929
|
+
const investmentPda = getRoundInvestmentPDA(projectPda, roundNumber, nftMint, program.programId);
|
|
930
|
+
const vestingPda = getRoundInvestorMilestoneVestingPDA(
|
|
931
|
+
projectPda,
|
|
932
|
+
roundNumber,
|
|
933
|
+
milestoneIndex,
|
|
934
|
+
investmentPda,
|
|
935
|
+
program.programId
|
|
936
|
+
);
|
|
937
|
+
return await getAccountNamespace(program).investorMilestoneVesting.fetch(vestingPda);
|
|
938
|
+
} catch (error) {
|
|
939
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
940
|
+
return null;
|
|
941
|
+
}
|
|
942
|
+
throw error;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
async function fetchFutureRoundVault(program, projectId) {
|
|
946
|
+
try {
|
|
947
|
+
const projectPda = getProjectPDA(projectId, program.programId);
|
|
948
|
+
const vaultPda = getFutureRoundVaultPDA(projectPda, program.programId);
|
|
949
|
+
return await getAccountNamespace(program).futureRoundVault.fetch(vaultPda);
|
|
950
|
+
} catch (error) {
|
|
951
|
+
if (error instanceof Error && error.message?.includes("Account does not exist")) {
|
|
952
|
+
return null;
|
|
953
|
+
}
|
|
954
|
+
throw error;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
function canClaimRoundEarlyTokens(investment, currentTimestamp, isDev = false) {
|
|
958
|
+
if (investment.roundNumber < 2) {
|
|
959
|
+
return { canClaim: false, reason: "R1 investments use claim_investor_early_tokens instruction" };
|
|
960
|
+
}
|
|
961
|
+
return canClaimEarlyTokens(investment, currentTimestamp, isDev);
|
|
962
|
+
}
|
|
963
|
+
function isR1FullyFunded(project) {
|
|
964
|
+
const raised = typeof project.totalRaised === "number" ? new BN(project.totalRaised) : project.totalRaised;
|
|
965
|
+
const goal = typeof project.fundingGoal === "number" ? new BN(project.fundingGoal) : project.fundingGoal;
|
|
966
|
+
return raised.gte(goal);
|
|
967
|
+
}
|
|
968
|
+
function isFundingRoundFullyFunded(fundingRound) {
|
|
969
|
+
const stateStr = getRoundStateString(fundingRound.state);
|
|
970
|
+
return ["funded", "inProgress", "inprogress", "completed"].includes(stateStr);
|
|
971
|
+
}
|
|
972
|
+
async function isRoundFullyFunded(program, projectId, roundNumber) {
|
|
973
|
+
if (roundNumber === 1) {
|
|
974
|
+
const project = await fetchProject(program, projectId);
|
|
975
|
+
if (!project) return false;
|
|
976
|
+
return isR1FullyFunded(project);
|
|
977
|
+
} else {
|
|
978
|
+
const fundingRound = await fetchFundingRound(program, projectId, roundNumber);
|
|
979
|
+
if (!fundingRound) return false;
|
|
980
|
+
return isFundingRoundFullyFunded(fundingRound);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
async function canOpenNextRound(program, projectId) {
|
|
984
|
+
const project = await fetchProject(program, projectId);
|
|
985
|
+
if (!project) {
|
|
986
|
+
return { canOpen: false, reason: "Project not found" };
|
|
987
|
+
}
|
|
988
|
+
const projectState = getProjectStateString(project.state);
|
|
989
|
+
if (!["inProgress", "inprogress", "completed"].includes(projectState)) {
|
|
990
|
+
return {
|
|
991
|
+
canOpen: false,
|
|
992
|
+
reason: `Project must be in InProgress or Completed state. Current: ${projectState}`
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
if (projectState !== "completed" && project.milestonesPassed === 0) {
|
|
996
|
+
return {
|
|
997
|
+
canOpen: false,
|
|
998
|
+
reason: "At least one milestone must pass before opening next round"
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
if (project.activeRound !== 0) {
|
|
1002
|
+
return {
|
|
1003
|
+
canOpen: false,
|
|
1004
|
+
reason: `Round ${project.activeRound} is already active`
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
const currentRound = project.roundCount;
|
|
1008
|
+
const isCurrentFunded = await isRoundFullyFunded(program, projectId, currentRound);
|
|
1009
|
+
if (!isCurrentFunded) {
|
|
1010
|
+
return {
|
|
1011
|
+
canOpen: false,
|
|
1012
|
+
reason: `Current round ${currentRound} must be fully funded before opening next round`
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
const tokenomics = await fetchTokenomics(program, projectId);
|
|
1016
|
+
if (!tokenomics) {
|
|
1017
|
+
return { canOpen: false, reason: "Tokenomics not found" };
|
|
1018
|
+
}
|
|
1019
|
+
if (tokenomics.futureRoundAllocationBps === 0) {
|
|
1020
|
+
return {
|
|
1021
|
+
canOpen: false,
|
|
1022
|
+
reason: "No future round allocation configured"
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
const remainingAllocation = tokenomics.futureRoundAllocationBps - (tokenomics.usedFutureRoundBps || 0);
|
|
1026
|
+
if (remainingAllocation <= 0) {
|
|
1027
|
+
return {
|
|
1028
|
+
canOpen: false,
|
|
1029
|
+
reason: "Future round allocation pool exhausted"
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
return {
|
|
1033
|
+
canOpen: true,
|
|
1034
|
+
nextRoundNumber: currentRound + 1
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
function getRemainingFutureRoundAllocation(tokenomics) {
|
|
1038
|
+
return tokenomics.futureRoundAllocationBps - (tokenomics.usedFutureRoundBps || 0);
|
|
1039
|
+
}
|
|
1040
|
+
function getRoundStateString(state) {
|
|
1041
|
+
if (typeof state === "object" && state !== null) {
|
|
1042
|
+
const keys = Object.keys(state);
|
|
1043
|
+
return keys[0]?.toLowerCase() ?? "unknown";
|
|
1044
|
+
}
|
|
1045
|
+
return "unknown";
|
|
1046
|
+
}
|
|
1047
|
+
var TOKEN_METADATA_PROGRAM_ID = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
|
|
1048
|
+
function ensurePublicKey(value) {
|
|
1049
|
+
if (value instanceof PublicKey) {
|
|
1050
|
+
return value;
|
|
1051
|
+
}
|
|
1052
|
+
return new PublicKey(String(value));
|
|
1053
|
+
}
|
|
1054
|
+
function getMethods(program) {
|
|
1055
|
+
return program.methods;
|
|
1056
|
+
}
|
|
1057
|
+
function getAccountNamespace2(program) {
|
|
1058
|
+
return program.account;
|
|
1059
|
+
}
|
|
1060
|
+
async function initializeAdmin(program, admin, payer) {
|
|
1061
|
+
return getMethods(program).initializeAdmin().accountsPartial({
|
|
1062
|
+
admin,
|
|
1063
|
+
payer
|
|
1064
|
+
}).rpc();
|
|
1065
|
+
}
|
|
1066
|
+
async function transferAdmin(program, adminKeypair, newAdmin) {
|
|
1067
|
+
return getMethods(program).transferAdmin().accountsPartial({
|
|
1068
|
+
authority: adminKeypair.publicKey,
|
|
1069
|
+
newAdmin
|
|
1070
|
+
}).signers([adminKeypair]).rpc();
|
|
1071
|
+
}
|
|
1072
|
+
async function acceptAdmin(program, newAuthority) {
|
|
1073
|
+
return getMethods(program).acceptAdmin().accountsPartial({
|
|
1074
|
+
newAuthority
|
|
1075
|
+
}).rpc();
|
|
1076
|
+
}
|
|
1077
|
+
function symbolToBytes(symbol) {
|
|
1078
|
+
const bytes = new Array(8).fill(0);
|
|
1079
|
+
const chars = symbol.toUpperCase().slice(0, 8);
|
|
1080
|
+
for (let i = 0; i < chars.length; i++) {
|
|
1081
|
+
bytes[i] = chars.charCodeAt(i);
|
|
1082
|
+
}
|
|
1083
|
+
return bytes;
|
|
1084
|
+
}
|
|
1085
|
+
var MIN_DEADLINE_DURATION_SECONDS_PROD = 604800;
|
|
1086
|
+
var MIN_DEADLINE_DURATION_SECONDS_DEV = 60;
|
|
1087
|
+
var MAX_DEADLINE_DURATION_SECONDS = 31536e3;
|
|
1088
|
+
function calculateDeadline(daysFromNow, isDev = false) {
|
|
1089
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
1090
|
+
const minDuration = isDev ? MIN_DEADLINE_DURATION_SECONDS_DEV : MIN_DEADLINE_DURATION_SECONDS_PROD;
|
|
1091
|
+
const daysInSeconds = daysFromNow * 24 * 60 * 60;
|
|
1092
|
+
const deadlineSeconds = nowSeconds + Math.max(daysInSeconds, minDuration);
|
|
1093
|
+
const maxDeadline = nowSeconds + MAX_DEADLINE_DURATION_SECONDS;
|
|
1094
|
+
return new BN(Math.min(deadlineSeconds, maxDeadline));
|
|
1095
|
+
}
|
|
1096
|
+
function minDeadline(isDev = false) {
|
|
1097
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
1098
|
+
const minDuration = isDev ? MIN_DEADLINE_DURATION_SECONDS_DEV : MIN_DEADLINE_DURATION_SECONDS_PROD;
|
|
1099
|
+
return new BN(nowSeconds + minDuration + 1);
|
|
1100
|
+
}
|
|
1101
|
+
function validateDeadline(deadline, isDev = false) {
|
|
1102
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
1103
|
+
const deadlineSeconds = deadline.toNumber();
|
|
1104
|
+
const minDuration = isDev ? MIN_DEADLINE_DURATION_SECONDS_DEV : MIN_DEADLINE_DURATION_SECONDS_PROD;
|
|
1105
|
+
const minDeadline2 = nowSeconds + minDuration;
|
|
1106
|
+
const maxDeadline = nowSeconds + MAX_DEADLINE_DURATION_SECONDS;
|
|
1107
|
+
if (deadlineSeconds < minDeadline2) {
|
|
1108
|
+
const minDays = isDev ? "60 seconds" : "7 days";
|
|
1109
|
+
return {
|
|
1110
|
+
valid: false,
|
|
1111
|
+
error: `Deadline must be at least ${minDays} from now`
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
if (deadlineSeconds > maxDeadline) {
|
|
1115
|
+
return {
|
|
1116
|
+
valid: false,
|
|
1117
|
+
error: "Deadline must be within 1 year from now"
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
return { valid: true };
|
|
1121
|
+
}
|
|
1122
|
+
async function initializeProject(program, args, founder) {
|
|
1123
|
+
return getMethods(program).initializeProject({
|
|
1124
|
+
projectId: args.projectId,
|
|
1125
|
+
fundingGoal: args.fundingGoal,
|
|
1126
|
+
metadataUri: args.metadataUri,
|
|
1127
|
+
tiers: args.tiers,
|
|
1128
|
+
tokenomics: {
|
|
1129
|
+
tokenSymbol: args.tokenomics.tokenSymbol,
|
|
1130
|
+
totalSupply: args.tokenomics.totalSupply,
|
|
1131
|
+
investorAllocationBps: args.tokenomics.investorAllocationBps,
|
|
1132
|
+
lpTokenAllocationBps: args.tokenomics.lpTokenAllocationBps,
|
|
1133
|
+
lpUsdcAllocationBps: args.tokenomics.lpUsdcAllocationBps,
|
|
1134
|
+
founderAllocationBps: args.tokenomics.founderAllocationBps ?? null,
|
|
1135
|
+
zemythAllocationBps: args.tokenomics.zemythAllocationBps ?? null,
|
|
1136
|
+
founderWallet: args.tokenomics.founderWallet ?? null,
|
|
601
1137
|
vestingDurationMonths: args.tokenomics.vestingDurationMonths ?? null,
|
|
602
|
-
cliffMonths: args.tokenomics.cliffMonths ?? null
|
|
1138
|
+
cliffMonths: args.tokenomics.cliffMonths ?? null,
|
|
1139
|
+
founderMilestoneVestingBps: args.tokenomics.founderMilestoneVestingBps ?? null,
|
|
1140
|
+
founderTimeVestingBps: args.tokenomics.founderTimeVestingBps ?? null,
|
|
1141
|
+
futureRoundAllocationBps: args.tokenomics.futureRoundAllocationBps ?? null
|
|
603
1142
|
},
|
|
604
|
-
milestone1Deadline: args.milestone1Deadline
|
|
605
|
-
|
|
1143
|
+
milestone1Deadline: args.milestone1Deadline,
|
|
1144
|
+
priceMultipliers: args.priceMultipliers ?? null
|
|
1145
|
+
}).accountsPartial({
|
|
606
1146
|
founder
|
|
607
1147
|
}).rpc();
|
|
608
1148
|
}
|
|
609
1149
|
async function submitForApproval(program, projectId, founder) {
|
|
610
1150
|
const projectPda = getProjectPDA(projectId, program.programId);
|
|
611
|
-
return getMethods(program).submitForApproval().
|
|
1151
|
+
return getMethods(program).submitForApproval().accountsPartial({
|
|
612
1152
|
project: projectPda,
|
|
613
1153
|
founder
|
|
614
1154
|
}).rpc();
|
|
@@ -624,7 +1164,12 @@ async function approveProject(program, args, adminKeypair) {
|
|
|
624
1164
|
const lpTokenVaultPda = getLpTokenVaultPDA(projectPda, program.programId);
|
|
625
1165
|
const treasuryVaultPda = getTreasuryVaultPDA(projectPda, program.programId);
|
|
626
1166
|
const lpUsdcVaultPda = getLpUsdcVaultPDA(projectPda, program.programId);
|
|
627
|
-
|
|
1167
|
+
const futureRoundTokenVaultPda = getFutureRoundTokenVaultPDA(projectPda, program.programId);
|
|
1168
|
+
const futureRoundVaultPda = getFutureRoundVaultPDA(projectPda, program.programId);
|
|
1169
|
+
const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({
|
|
1170
|
+
units: 4e5
|
|
1171
|
+
});
|
|
1172
|
+
return getMethods(program).approveProject().accountsPartial({
|
|
628
1173
|
project: projectPda,
|
|
629
1174
|
tokenomics: tokenomicsPda,
|
|
630
1175
|
tokenVault: tokenVaultPda,
|
|
@@ -635,10 +1180,12 @@ async function approveProject(program, args, adminKeypair) {
|
|
|
635
1180
|
lpTokenVault: lpTokenVaultPda,
|
|
636
1181
|
treasuryVault: treasuryVaultPda,
|
|
637
1182
|
lpUsdcVault: lpUsdcVaultPda,
|
|
1183
|
+
futureRoundTokenVault: futureRoundTokenVaultPda,
|
|
1184
|
+
futureRoundVault: futureRoundVaultPda,
|
|
638
1185
|
usdcMint: args.usdcMint,
|
|
639
1186
|
authority: adminKeypair.publicKey,
|
|
640
1187
|
payer: adminKeypair.publicKey
|
|
641
|
-
}).signers([adminKeypair]).rpc();
|
|
1188
|
+
}).preInstructions([computeBudgetIx]).signers([adminKeypair]).rpc();
|
|
642
1189
|
}
|
|
643
1190
|
async function createMilestone(program, args, founder) {
|
|
644
1191
|
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
@@ -646,8 +1193,11 @@ async function createMilestone(program, args, founder) {
|
|
|
646
1193
|
return getMethods(program).createMilestone({
|
|
647
1194
|
milestoneIndex: args.milestoneIndex,
|
|
648
1195
|
percentage: args.percentage,
|
|
649
|
-
description: args.description
|
|
650
|
-
|
|
1196
|
+
description: args.description,
|
|
1197
|
+
vestingDurationMonths: args.vestingDurationMonths ?? null,
|
|
1198
|
+
cliffMonths: args.cliffMonths ?? null,
|
|
1199
|
+
instantReleaseBps: args.instantReleaseBps ?? null
|
|
1200
|
+
}).accountsPartial({
|
|
651
1201
|
project: projectPda,
|
|
652
1202
|
milestone: milestonePda,
|
|
653
1203
|
founder
|
|
@@ -656,7 +1206,7 @@ async function createMilestone(program, args, founder) {
|
|
|
656
1206
|
async function submitMilestone(program, projectId, milestoneIndex, founder) {
|
|
657
1207
|
const projectPda = getProjectPDA(projectId, program.programId);
|
|
658
1208
|
const milestonePda = getMilestonePDA(projectPda, milestoneIndex, program.programId);
|
|
659
|
-
return getMethods(program).submitMilestone().
|
|
1209
|
+
return getMethods(program).submitMilestone().accountsPartial({
|
|
660
1210
|
project: projectPda,
|
|
661
1211
|
milestone: milestonePda,
|
|
662
1212
|
founder
|
|
@@ -677,7 +1227,7 @@ async function voteOnMilestone(program, args, voter) {
|
|
|
677
1227
|
// allowOwnerOffCurve
|
|
678
1228
|
TOKEN_PROGRAM_ID
|
|
679
1229
|
);
|
|
680
|
-
return getMethods(program).voteOnMilestone({ choice: args.choice }).
|
|
1230
|
+
return getMethods(program).voteOnMilestone({ choice: args.choice }).accountsPartial({
|
|
681
1231
|
milestone: milestonePda,
|
|
682
1232
|
project: projectPda,
|
|
683
1233
|
investment: investmentPda,
|
|
@@ -690,7 +1240,7 @@ async function voteOnMilestone(program, args, voter) {
|
|
|
690
1240
|
async function finalizeVoting(program, projectId, milestoneIndex) {
|
|
691
1241
|
const projectPda = getProjectPDA(projectId, program.programId);
|
|
692
1242
|
const milestonePda = getMilestonePDA(projectPda, milestoneIndex, program.programId);
|
|
693
|
-
return getMethods(program).finalizeVoting().
|
|
1243
|
+
return getMethods(program).finalizeVoting().accountsPartial({
|
|
694
1244
|
project: projectPda,
|
|
695
1245
|
milestone: milestonePda
|
|
696
1246
|
}).rpc();
|
|
@@ -703,7 +1253,7 @@ async function claimMilestoneFunds(program, args, founder) {
|
|
|
703
1253
|
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
704
1254
|
const lpUsdcVaultPda = getLpUsdcVaultPDA(projectPda, program.programId);
|
|
705
1255
|
const nextMilestonePda = args.nextMilestonePda ?? (args.nextMilestoneDeadline.gt(new BN(0)) ? getMilestonePDA(projectPda, args.milestoneIndex + 1, program.programId) : null);
|
|
706
|
-
return getMethods(program).claimMilestoneFunds({ nextMilestoneDeadline: args.nextMilestoneDeadline }).
|
|
1256
|
+
return getMethods(program).claimMilestoneFunds({ nextMilestoneDeadline: args.nextMilestoneDeadline }).accountsPartial({
|
|
707
1257
|
milestone: milestonePda,
|
|
708
1258
|
project: projectPda,
|
|
709
1259
|
founder,
|
|
@@ -721,7 +1271,7 @@ async function claimMilestoneFunds(program, args, founder) {
|
|
|
721
1271
|
async function resubmitMilestone(program, args, founder) {
|
|
722
1272
|
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
723
1273
|
const milestonePda = getMilestonePDA(projectPda, args.milestoneIndex, program.programId);
|
|
724
|
-
return getMethods(program).resubmitMilestone().
|
|
1274
|
+
return getMethods(program).resubmitMilestone().accountsPartial({
|
|
725
1275
|
project: projectPda,
|
|
726
1276
|
milestone: milestonePda,
|
|
727
1277
|
founder
|
|
@@ -733,7 +1283,7 @@ async function setMilestoneDeadline(program, args, founder) {
|
|
|
733
1283
|
return getMethods(program).setMilestoneDeadline({
|
|
734
1284
|
milestoneIndex: args.milestoneIndex,
|
|
735
1285
|
deadline: args.deadline
|
|
736
|
-
}).
|
|
1286
|
+
}).accountsPartial({
|
|
737
1287
|
project: projectPda,
|
|
738
1288
|
milestone: milestonePda,
|
|
739
1289
|
founder
|
|
@@ -745,7 +1295,7 @@ async function extendMilestoneDeadline(program, args, founder) {
|
|
|
745
1295
|
return getMethods(program).extendMilestoneDeadline({
|
|
746
1296
|
milestoneIndex: args.milestoneIndex,
|
|
747
1297
|
newDeadline: args.newDeadline
|
|
748
|
-
}).
|
|
1298
|
+
}).accountsPartial({
|
|
749
1299
|
project: projectPda,
|
|
750
1300
|
milestone: milestonePda,
|
|
751
1301
|
founder
|
|
@@ -783,7 +1333,7 @@ async function invest(program, args, investor) {
|
|
|
783
1333
|
const masterEdition = getMasterEditionPDA(nftMint);
|
|
784
1334
|
const [programAuthority] = getProgramAuthorityPDA(program.programId);
|
|
785
1335
|
const firstMilestonePda = getMilestonePDA(projectPda, 0, program.programId);
|
|
786
|
-
return getMethods(program).invest({ amount: args.amount }).
|
|
1336
|
+
return getMethods(program).invest({ amount: args.amount }).accountsPartial({
|
|
787
1337
|
project: projectPda,
|
|
788
1338
|
firstMilestone: firstMilestonePda,
|
|
789
1339
|
nftMint,
|
|
@@ -810,7 +1360,7 @@ async function cancelInvestment(program, args, investor) {
|
|
|
810
1360
|
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
811
1361
|
const investmentPda = getInvestmentPDA(projectPda, nftMintPubkey, program.programId);
|
|
812
1362
|
const escrowPda = getEscrowPDA(args.projectId, program.programId);
|
|
813
|
-
return getMethods(program).cancelInvestment().
|
|
1363
|
+
return getMethods(program).cancelInvestment().accountsPartial({
|
|
814
1364
|
investor,
|
|
815
1365
|
project: projectPda,
|
|
816
1366
|
investment: investmentPda,
|
|
@@ -829,7 +1379,7 @@ async function proposePivot(program, args, founder) {
|
|
|
829
1379
|
return getMethods(program).proposePivot({
|
|
830
1380
|
newMetadataUri: args.newMetadataUri,
|
|
831
1381
|
newMilestones: args.newMilestones
|
|
832
|
-
}).
|
|
1382
|
+
}).accountsPartial({
|
|
833
1383
|
project: projectPda,
|
|
834
1384
|
founder,
|
|
835
1385
|
pivotProposal: pivotProposalPda,
|
|
@@ -847,7 +1397,7 @@ async function approvePivot(program, projectId, adminKeypair) {
|
|
|
847
1397
|
const pivotCount = projectAccount.pivotCount || 0;
|
|
848
1398
|
pivotProposalPda = getPivotProposalPDA(projectPda, pivotCount, program.programId);
|
|
849
1399
|
}
|
|
850
|
-
return getMethods(program).approvePivot().
|
|
1400
|
+
return getMethods(program).approvePivot().accountsPartial({
|
|
851
1401
|
moderator: adminKeypair.publicKey,
|
|
852
1402
|
project: projectPda,
|
|
853
1403
|
pivotProposal: pivotProposalPda
|
|
@@ -870,7 +1420,7 @@ async function withdrawFromPivot(program, args, investor) {
|
|
|
870
1420
|
isSigner: false,
|
|
871
1421
|
isWritable: false
|
|
872
1422
|
}));
|
|
873
|
-
return getMethods(program).withdrawFromPivot().
|
|
1423
|
+
return getMethods(program).withdrawFromPivot().accountsPartial({
|
|
874
1424
|
investor,
|
|
875
1425
|
project: projectPda,
|
|
876
1426
|
pivotProposal: pivotProposalPda,
|
|
@@ -890,7 +1440,7 @@ async function finalizePivot(program, args, authority) {
|
|
|
890
1440
|
isSigner: false,
|
|
891
1441
|
isWritable: true
|
|
892
1442
|
}));
|
|
893
|
-
return getMethods(program).finalizePivot().
|
|
1443
|
+
return getMethods(program).finalizePivot().accountsPartial({
|
|
894
1444
|
authority,
|
|
895
1445
|
project: projectPda,
|
|
896
1446
|
pivotProposal: pivotProposalPda
|
|
@@ -901,14 +1451,14 @@ async function setTgeDate(program, args, founder) {
|
|
|
901
1451
|
return getMethods(program).setTgeDate({
|
|
902
1452
|
tgeDate: args.tgeDate,
|
|
903
1453
|
tokenMint: args.tokenMint
|
|
904
|
-
}).
|
|
1454
|
+
}).accountsPartial({
|
|
905
1455
|
project: projectPda,
|
|
906
1456
|
founder
|
|
907
1457
|
}).rpc();
|
|
908
1458
|
}
|
|
909
1459
|
async function depositTokens(program, args, founder) {
|
|
910
1460
|
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
911
|
-
return getMethods(program).depositTokens({ amount: args.amount }).
|
|
1461
|
+
return getMethods(program).depositTokens({ amount: args.amount }).accountsPartial({
|
|
912
1462
|
project: projectPda,
|
|
913
1463
|
tokenMint: args.tokenMint,
|
|
914
1464
|
founderTokenAccount: args.founderTokenAccount,
|
|
@@ -919,7 +1469,7 @@ async function claimTokens(program, args, investor) {
|
|
|
919
1469
|
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
920
1470
|
const investmentPda = getInvestmentPDA(projectPda, args.nftMint, program.programId);
|
|
921
1471
|
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
922
|
-
return getMethods(program).claimTokens().
|
|
1472
|
+
return getMethods(program).claimTokens().accountsPartial({
|
|
923
1473
|
investor,
|
|
924
1474
|
project: projectPda,
|
|
925
1475
|
investment: investmentPda,
|
|
@@ -934,7 +1484,7 @@ async function reportScam(program, args, reporter) {
|
|
|
934
1484
|
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
935
1485
|
const tgeEscrowPda = getTgeEscrowPDA(projectPda, program.programId);
|
|
936
1486
|
const investmentPda = getInvestmentPDA(projectPda, args.nftMint, program.programId);
|
|
937
|
-
return getMethods(program).reportScam().
|
|
1487
|
+
return getMethods(program).reportScam().accountsPartial({
|
|
938
1488
|
tgeEscrow: tgeEscrowPda,
|
|
939
1489
|
project: projectPda,
|
|
940
1490
|
investment: investmentPda,
|
|
@@ -945,7 +1495,7 @@ async function reportScam(program, args, reporter) {
|
|
|
945
1495
|
async function releaseHoldback(program, args) {
|
|
946
1496
|
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
947
1497
|
const tgeEscrowPda = getTgeEscrowPDA(projectPda, program.programId);
|
|
948
|
-
return getMethods(program).releaseHoldback().
|
|
1498
|
+
return getMethods(program).releaseHoldback().accountsPartial({
|
|
949
1499
|
tgeEscrow: tgeEscrowPda,
|
|
950
1500
|
project: projectPda,
|
|
951
1501
|
founderTokenAccount: args.founderTokenAccount
|
|
@@ -954,7 +1504,7 @@ async function releaseHoldback(program, args) {
|
|
|
954
1504
|
async function checkAbandonment(program, projectId, milestoneIndex = 0) {
|
|
955
1505
|
const projectPda = getProjectPDA(projectId, program.programId);
|
|
956
1506
|
const milestonePda = getMilestonePDA(projectPda, milestoneIndex, program.programId);
|
|
957
|
-
return getMethods(program).checkAbandonment().
|
|
1507
|
+
return getMethods(program).checkAbandonment().accountsPartial({
|
|
958
1508
|
project: projectPda,
|
|
959
1509
|
milestone: milestonePda
|
|
960
1510
|
}).rpc();
|
|
@@ -973,7 +1523,7 @@ async function claimRefund(program, args, investor) {
|
|
|
973
1523
|
isSigner: false
|
|
974
1524
|
});
|
|
975
1525
|
}
|
|
976
|
-
return getMethods(program).claimRefund().
|
|
1526
|
+
return getMethods(program).claimRefund().accountsPartial({
|
|
977
1527
|
project: projectPda,
|
|
978
1528
|
investment: investmentPda,
|
|
979
1529
|
nftMint: nftMintPubkey,
|
|
@@ -996,7 +1546,7 @@ async function claimInvestorTokens(program, args, investor) {
|
|
|
996
1546
|
false,
|
|
997
1547
|
TOKEN_PROGRAM_ID
|
|
998
1548
|
);
|
|
999
|
-
return getMethods(program).claimInvestorTokens({ milestoneIndex: args.milestoneIndex }).
|
|
1549
|
+
return getMethods(program).claimInvestorTokens({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
1000
1550
|
investor,
|
|
1001
1551
|
project: projectPda,
|
|
1002
1552
|
tokenVault: tokenVaultPda,
|
|
@@ -1018,7 +1568,7 @@ async function distributeTokens(program, args, payer) {
|
|
|
1018
1568
|
{ pubkey: inv.investmentPda, isSigner: false, isWritable: true },
|
|
1019
1569
|
{ pubkey: inv.investorTokenAccount, isSigner: false, isWritable: true }
|
|
1020
1570
|
]);
|
|
1021
|
-
return getMethods(program).distributeTokens({ milestoneIndex: args.milestoneIndex }).
|
|
1571
|
+
return getMethods(program).distributeTokens({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
1022
1572
|
project: projectPda,
|
|
1023
1573
|
tokenVault: tokenVaultPda,
|
|
1024
1574
|
investorVault: investorVaultPda,
|
|
@@ -1030,7 +1580,7 @@ async function distributeTokens(program, args, payer) {
|
|
|
1030
1580
|
async function completeDistribution(program, args, payer) {
|
|
1031
1581
|
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1032
1582
|
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1033
|
-
return getMethods(program).completeDistribution({ milestoneIndex: args.milestoneIndex }).
|
|
1583
|
+
return getMethods(program).completeDistribution({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
1034
1584
|
project: projectPda,
|
|
1035
1585
|
tokenVault: tokenVaultPda,
|
|
1036
1586
|
payer
|
|
@@ -1061,7 +1611,7 @@ async function initializeFounderVesting(program, args, payer) {
|
|
|
1061
1611
|
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
1062
1612
|
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1063
1613
|
const founderVestingPda = getFounderVestingPDA(projectPda, program.programId);
|
|
1064
|
-
return getMethods(program).initializeFounderVesting().
|
|
1614
|
+
return getMethods(program).initializeFounderVesting().accountsPartial({
|
|
1065
1615
|
project: projectPda,
|
|
1066
1616
|
tokenomics: tokenomicsPda,
|
|
1067
1617
|
tokenVault: tokenVaultPda,
|
|
@@ -1076,7 +1626,7 @@ async function claimVestedTokens(program, args, founder) {
|
|
|
1076
1626
|
const founderVestingPda = getFounderVestingPDA(projectPda, program.programId);
|
|
1077
1627
|
const founderVaultPda = getFounderVaultPDA(projectPda, program.programId);
|
|
1078
1628
|
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
1079
|
-
return getMethods(program).claimVestedTokens().
|
|
1629
|
+
return getMethods(program).claimVestedTokens().accountsPartial({
|
|
1080
1630
|
project: projectPda,
|
|
1081
1631
|
tokenVault: tokenVaultPda,
|
|
1082
1632
|
founderVesting: founderVestingPda,
|
|
@@ -1091,7 +1641,7 @@ async function forceCompleteDistribution(program, args, adminKeypair) {
|
|
|
1091
1641
|
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1092
1642
|
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1093
1643
|
const adminConfigPda = getAdminConfigPDA(program.programId);
|
|
1094
|
-
return getMethods(program).forceCompleteDistribution().
|
|
1644
|
+
return getMethods(program).forceCompleteDistribution().accountsPartial({
|
|
1095
1645
|
admin: adminKeypair.publicKey,
|
|
1096
1646
|
adminConfig: adminConfigPda,
|
|
1097
1647
|
project: projectPda,
|
|
@@ -1111,7 +1661,7 @@ async function claimMissedUnlock(program, args, claimer) {
|
|
|
1111
1661
|
false,
|
|
1112
1662
|
TOKEN_PROGRAM_ID
|
|
1113
1663
|
);
|
|
1114
|
-
return getMethods(program).claimMissedUnlock({ milestoneIndex: args.milestoneIndex }).
|
|
1664
|
+
return getMethods(program).claimMissedUnlock({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
1115
1665
|
claimer,
|
|
1116
1666
|
project: projectPda,
|
|
1117
1667
|
tokenVault: tokenVaultPda,
|
|
@@ -1124,70 +1674,627 @@ async function claimMissedUnlock(program, args, claimer) {
|
|
|
1124
1674
|
tokenProgram: TOKEN_PROGRAM_ID
|
|
1125
1675
|
}).rpc();
|
|
1126
1676
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1677
|
+
async function addSubAllocation(program, args, founder) {
|
|
1678
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1679
|
+
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
1680
|
+
return getMethods(program).addSubAllocation({
|
|
1681
|
+
name: args.name,
|
|
1682
|
+
bps: args.bps,
|
|
1683
|
+
recipient: args.recipient,
|
|
1684
|
+
vestingMonths: args.vestingMonths,
|
|
1685
|
+
cliffMonths: args.cliffMonths
|
|
1686
|
+
}).accountsPartial({
|
|
1687
|
+
project: projectPda,
|
|
1688
|
+
tokenomics: tokenomicsPda,
|
|
1689
|
+
founder
|
|
1690
|
+
}).rpc();
|
|
1691
|
+
}
|
|
1692
|
+
async function proposeAllocationChange(program, args, founder) {
|
|
1693
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1694
|
+
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
1695
|
+
const tokenomics = await getAccountNamespace2(program).tokenomics.fetch(tokenomicsPda);
|
|
1696
|
+
const proposalIndex = tokenomics.proposalCount || 0;
|
|
1697
|
+
const proposalPda = getAllocationProposalPDA(projectPda, proposalIndex, program.programId);
|
|
1698
|
+
return getMethods(program).proposeAllocationChange({
|
|
1699
|
+
name: args.name,
|
|
1700
|
+
bps: args.bps,
|
|
1701
|
+
recipient: args.recipient,
|
|
1702
|
+
vestingMonths: args.vestingMonths,
|
|
1703
|
+
cliffMonths: args.cliffMonths
|
|
1704
|
+
}).accountsPartial({
|
|
1705
|
+
project: projectPda,
|
|
1706
|
+
tokenomics: tokenomicsPda,
|
|
1707
|
+
proposal: proposalPda,
|
|
1708
|
+
founder,
|
|
1709
|
+
systemProgram: SystemProgram.programId
|
|
1710
|
+
}).rpc();
|
|
1711
|
+
}
|
|
1712
|
+
async function voteAllocationChange(program, args, voter) {
|
|
1713
|
+
const nftMintPubkey = ensurePublicKey(args.nftMint);
|
|
1714
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1715
|
+
const proposalPda = getAllocationProposalPDA(projectPda, args.proposalIndex, program.programId);
|
|
1716
|
+
const investmentPda = getInvestmentPDA(projectPda, nftMintPubkey, program.programId);
|
|
1717
|
+
const votePda = getAllocationVotePDA(proposalPda, nftMintPubkey, program.programId);
|
|
1718
|
+
const investorNftAccount = getAssociatedTokenAddressSync(
|
|
1719
|
+
nftMintPubkey,
|
|
1720
|
+
voter,
|
|
1721
|
+
false,
|
|
1722
|
+
TOKEN_PROGRAM_ID
|
|
1723
|
+
);
|
|
1724
|
+
return getMethods(program).voteAllocationChange({ voteFor: args.voteFor }).accountsPartial({
|
|
1725
|
+
project: projectPda,
|
|
1726
|
+
proposal: proposalPda,
|
|
1727
|
+
investment: investmentPda,
|
|
1728
|
+
nftMint: nftMintPubkey,
|
|
1729
|
+
investorNftAccount,
|
|
1730
|
+
voteRecord: votePda,
|
|
1731
|
+
voter,
|
|
1732
|
+
systemProgram: SystemProgram.programId
|
|
1733
|
+
}).rpc();
|
|
1734
|
+
}
|
|
1735
|
+
async function executeAllocationChange(program, args, executor) {
|
|
1736
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1737
|
+
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
1738
|
+
const proposalPda = getAllocationProposalPDA(projectPda, args.proposalIndex, program.programId);
|
|
1739
|
+
return getMethods(program).executeAllocationChange().accountsPartial({
|
|
1740
|
+
project: projectPda,
|
|
1741
|
+
tokenomics: tokenomicsPda,
|
|
1742
|
+
proposal: proposalPda,
|
|
1743
|
+
executor
|
|
1744
|
+
}).rpc();
|
|
1745
|
+
}
|
|
1746
|
+
async function claimEarlyTokens(program, args, investor) {
|
|
1747
|
+
const nftMintPubkey = ensurePublicKey(args.nftMint);
|
|
1748
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1749
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1750
|
+
const investmentPda = getInvestmentPDA(projectPda, nftMintPubkey, program.programId);
|
|
1751
|
+
const investorVaultPda = getInvestorVaultPDA(projectPda, program.programId);
|
|
1752
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
1753
|
+
const investorNftAccount = getAssociatedTokenAddressSync(
|
|
1754
|
+
nftMintPubkey,
|
|
1755
|
+
investor,
|
|
1756
|
+
false,
|
|
1757
|
+
TOKEN_PROGRAM_ID
|
|
1758
|
+
);
|
|
1759
|
+
return getMethods(program).claimEarlyTokens().accountsPartial({
|
|
1760
|
+
investor,
|
|
1761
|
+
project: projectPda,
|
|
1762
|
+
tokenVault: tokenVaultPda,
|
|
1763
|
+
investment: investmentPda,
|
|
1764
|
+
nftMint: nftMintPubkey,
|
|
1765
|
+
investorNftAccount,
|
|
1766
|
+
investorVault: investorVaultPda,
|
|
1767
|
+
investorTokenAccount: args.investorTokenAccount,
|
|
1768
|
+
vaultAuthority: vaultAuthorityPda,
|
|
1769
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
1770
|
+
}).rpc();
|
|
1771
|
+
}
|
|
1772
|
+
async function claimFounderEarlyTokens(program, args, founder) {
|
|
1773
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1774
|
+
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
1775
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1776
|
+
const founderVaultPda = getFounderVaultPDA(projectPda, program.programId);
|
|
1777
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
1778
|
+
return getMethods(program).claimFounderEarlyTokens().accountsPartial({
|
|
1779
|
+
founder,
|
|
1780
|
+
project: projectPda,
|
|
1781
|
+
tokenomics: tokenomicsPda,
|
|
1782
|
+
tokenVault: tokenVaultPda,
|
|
1783
|
+
founderVault: founderVaultPda,
|
|
1784
|
+
founderTokenAccount: args.founderTokenAccount,
|
|
1785
|
+
vaultAuthority: vaultAuthorityPda,
|
|
1786
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
1787
|
+
}).rpc();
|
|
1788
|
+
}
|
|
1789
|
+
async function claimFounderMilestoneTokens(program, args, founder) {
|
|
1790
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1791
|
+
const milestonePda = getMilestonePDA(projectPda, args.milestoneIndex, program.programId);
|
|
1792
|
+
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
1793
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1794
|
+
const founderVaultPda = getFounderVaultPDA(projectPda, program.programId);
|
|
1795
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
1796
|
+
return getMethods(program).claimFounderMilestoneTokens({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
1797
|
+
founder,
|
|
1798
|
+
project: projectPda,
|
|
1799
|
+
milestone: milestonePda,
|
|
1800
|
+
tokenomics: tokenomicsPda,
|
|
1801
|
+
tokenVault: tokenVaultPda,
|
|
1802
|
+
founderVault: founderVaultPda,
|
|
1803
|
+
founderTokenAccount: args.founderTokenAccount,
|
|
1804
|
+
vaultAuthority: vaultAuthorityPda,
|
|
1805
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
1806
|
+
}).rpc();
|
|
1807
|
+
}
|
|
1808
|
+
async function initializeSubAllocationVesting(program, args, payer) {
|
|
1809
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1810
|
+
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
1811
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1812
|
+
const subAllocationVestingPda = getSubAllocationVestingPDA(projectPda, args.subAllocationId, program.programId);
|
|
1813
|
+
return getMethods(program).initializeSubAllocationVesting({ subAllocationId: args.subAllocationId }).accountsPartial({
|
|
1814
|
+
project: projectPda,
|
|
1815
|
+
tokenomics: tokenomicsPda,
|
|
1816
|
+
tokenVault: tokenVaultPda,
|
|
1817
|
+
subAllocationVesting: subAllocationVestingPda,
|
|
1818
|
+
payer,
|
|
1819
|
+
systemProgram: SystemProgram.programId
|
|
1820
|
+
}).rpc();
|
|
1821
|
+
}
|
|
1822
|
+
async function claimSubAllocationTokens(program, args, recipient) {
|
|
1823
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1824
|
+
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
1825
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1826
|
+
const subAllocationVestingPda = getSubAllocationVestingPDA(projectPda, args.subAllocationId, program.programId);
|
|
1827
|
+
const treasuryVaultPda = getTreasuryVaultPDA(projectPda, program.programId);
|
|
1828
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
1829
|
+
return getMethods(program).claimSubAllocationTokens({ subAllocationId: args.subAllocationId }).accountsPartial({
|
|
1830
|
+
project: projectPda,
|
|
1831
|
+
tokenomics: tokenomicsPda,
|
|
1832
|
+
tokenVault: tokenVaultPda,
|
|
1833
|
+
subAllocationVesting: subAllocationVestingPda,
|
|
1834
|
+
reserveVault: treasuryVaultPda,
|
|
1835
|
+
vaultAuthority: vaultAuthorityPda,
|
|
1836
|
+
recipientTokenAccount: args.recipientTokenAccount,
|
|
1837
|
+
recipient,
|
|
1838
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
1839
|
+
}).rpc();
|
|
1840
|
+
}
|
|
1841
|
+
async function claimMilestoneInstantTokens(program, args, investor) {
|
|
1842
|
+
const nftMintPubkey = ensurePublicKey(args.nftMint);
|
|
1843
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1844
|
+
const milestonePda = getMilestonePDA(projectPda, args.milestoneIndex, program.programId);
|
|
1845
|
+
const investmentPda = getInvestmentPDA(projectPda, nftMintPubkey, program.programId);
|
|
1846
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1847
|
+
const vestingPda = getInvestorMilestoneVestingPDA(projectPda, args.milestoneIndex, investmentPda, program.programId);
|
|
1848
|
+
const investorVaultPda = getInvestorVaultPDA(projectPda, program.programId);
|
|
1849
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
1850
|
+
const investorNftAccount = getAssociatedTokenAddressSync(
|
|
1851
|
+
nftMintPubkey,
|
|
1852
|
+
investor,
|
|
1853
|
+
false,
|
|
1854
|
+
TOKEN_PROGRAM_ID
|
|
1855
|
+
);
|
|
1856
|
+
return getMethods(program).claimMilestoneInstantTokens({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
1857
|
+
investor,
|
|
1858
|
+
project: projectPda,
|
|
1859
|
+
milestone: milestonePda,
|
|
1860
|
+
investment: investmentPda,
|
|
1861
|
+
tokenVault: tokenVaultPda,
|
|
1862
|
+
vesting: vestingPda,
|
|
1863
|
+
nftMint: nftMintPubkey,
|
|
1864
|
+
investorNftAccount,
|
|
1865
|
+
investorVault: investorVaultPda,
|
|
1866
|
+
investorTokenAccount: args.investorTokenAccount,
|
|
1867
|
+
vaultAuthority: vaultAuthorityPda,
|
|
1868
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1869
|
+
systemProgram: SystemProgram.programId
|
|
1870
|
+
}).rpc();
|
|
1871
|
+
}
|
|
1872
|
+
async function claimMilestoneVestedTokens(program, args, investor) {
|
|
1873
|
+
const nftMintPubkey = ensurePublicKey(args.nftMint);
|
|
1874
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1875
|
+
const milestonePda = getMilestonePDA(projectPda, args.milestoneIndex, program.programId);
|
|
1876
|
+
const investmentPda = getInvestmentPDA(projectPda, nftMintPubkey, program.programId);
|
|
1877
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1878
|
+
const vestingPda = getInvestorMilestoneVestingPDA(projectPda, args.milestoneIndex, investmentPda, program.programId);
|
|
1879
|
+
const investorVaultPda = getInvestorVaultPDA(projectPda, program.programId);
|
|
1880
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
1881
|
+
const investorNftAccount = getAssociatedTokenAddressSync(
|
|
1882
|
+
nftMintPubkey,
|
|
1883
|
+
investor,
|
|
1884
|
+
false,
|
|
1885
|
+
TOKEN_PROGRAM_ID
|
|
1886
|
+
);
|
|
1887
|
+
return getMethods(program).claimMilestoneVestedTokens({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
1888
|
+
investor,
|
|
1889
|
+
project: projectPda,
|
|
1890
|
+
milestone: milestonePda,
|
|
1891
|
+
investment: investmentPda,
|
|
1892
|
+
tokenVault: tokenVaultPda,
|
|
1893
|
+
vesting: vestingPda,
|
|
1894
|
+
nftMint: nftMintPubkey,
|
|
1895
|
+
investorNftAccount,
|
|
1896
|
+
investorVault: investorVaultPda,
|
|
1897
|
+
investorTokenAccount: args.investorTokenAccount,
|
|
1898
|
+
vaultAuthority: vaultAuthorityPda,
|
|
1899
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
1900
|
+
}).rpc();
|
|
1901
|
+
}
|
|
1902
|
+
async function claimFounderMsInstantTokens(program, args, founder) {
|
|
1903
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1904
|
+
const milestonePda = getMilestonePDA(projectPda, args.milestoneIndex, program.programId);
|
|
1905
|
+
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
1906
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1907
|
+
const vestingPda = getFounderMilestoneVestingPDA(projectPda, args.milestoneIndex, program.programId);
|
|
1908
|
+
const founderVaultPda = getFounderVaultPDA(projectPda, program.programId);
|
|
1909
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
1910
|
+
return getMethods(program).claimFounderMsInstantTokens({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
1911
|
+
founder,
|
|
1912
|
+
project: projectPda,
|
|
1913
|
+
tokenomics: tokenomicsPda,
|
|
1914
|
+
milestone: milestonePda,
|
|
1915
|
+
tokenVault: tokenVaultPda,
|
|
1916
|
+
vesting: vestingPda,
|
|
1917
|
+
founderVault: founderVaultPda,
|
|
1918
|
+
founderTokenAccount: args.founderTokenAccount,
|
|
1919
|
+
vaultAuthority: vaultAuthorityPda,
|
|
1920
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1921
|
+
systemProgram: SystemProgram.programId
|
|
1922
|
+
}).rpc();
|
|
1923
|
+
}
|
|
1924
|
+
async function claimFounderMsVestedTokens(program, args, founder) {
|
|
1925
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1926
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
1927
|
+
const vestingPda = getFounderMilestoneVestingPDA(projectPda, args.milestoneIndex, program.programId);
|
|
1928
|
+
const founderVaultPda = getFounderVaultPDA(projectPda, program.programId);
|
|
1929
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
1930
|
+
return getMethods(program).claimFounderMsVestedTokens({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
1931
|
+
founder,
|
|
1932
|
+
project: projectPda,
|
|
1933
|
+
tokenVault: tokenVaultPda,
|
|
1934
|
+
vesting: vestingPda,
|
|
1935
|
+
founderVault: founderVaultPda,
|
|
1936
|
+
founderTokenAccount: args.founderTokenAccount,
|
|
1937
|
+
vaultAuthority: vaultAuthorityPda,
|
|
1938
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
1939
|
+
}).rpc();
|
|
1940
|
+
}
|
|
1941
|
+
function getRoundEscrowAuthorityPDA(projectPda, roundNumber, programId) {
|
|
1942
|
+
return PublicKey.findProgramAddressSync(
|
|
1943
|
+
[
|
|
1944
|
+
Buffer.from("round_escrow"),
|
|
1945
|
+
projectPda.toBuffer(),
|
|
1946
|
+
Buffer.from([roundNumber]),
|
|
1947
|
+
Buffer.from("authority")
|
|
1948
|
+
],
|
|
1949
|
+
programId
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
async function openFundingRound(program, args, founder) {
|
|
1953
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1954
|
+
const tokenomicsPda = getTokenomicsPDA(projectPda, program.programId);
|
|
1955
|
+
const project = await getAccountNamespace2(program).project.fetch(projectPda);
|
|
1956
|
+
const newRoundNumber = (project.roundCount || 1) + 1;
|
|
1957
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, newRoundNumber, program.programId);
|
|
1958
|
+
const roundEscrowPda = getRoundEscrowPDA(projectPda, newRoundNumber, program.programId);
|
|
1959
|
+
const [roundEscrowAuthorityPda] = getRoundEscrowAuthorityPDA(projectPda, newRoundNumber, program.programId);
|
|
1960
|
+
const remainingAccounts = args.milestones.map((_, i) => {
|
|
1961
|
+
const milestonePda = getRoundMilestonePDA(projectPda, newRoundNumber, i, program.programId);
|
|
1962
|
+
return {
|
|
1963
|
+
pubkey: milestonePda,
|
|
1964
|
+
isSigner: false,
|
|
1965
|
+
isWritable: true
|
|
1966
|
+
};
|
|
1967
|
+
});
|
|
1968
|
+
const milestonesParam = args.milestones.map((m) => ({
|
|
1969
|
+
percentage: m.percentage,
|
|
1970
|
+
description: m.description,
|
|
1971
|
+
vestingDurationMonths: m.vestingDurationMonths ?? null,
|
|
1972
|
+
cliffMonths: m.cliffMonths ?? null,
|
|
1973
|
+
instantReleaseBps: m.instantReleaseBps ?? null
|
|
1974
|
+
}));
|
|
1975
|
+
return getMethods(program).openFundingRound({
|
|
1976
|
+
roundAllocationBps: args.roundAllocationBps,
|
|
1977
|
+
fundingGoal: args.fundingGoal,
|
|
1978
|
+
tiers: args.tiers,
|
|
1979
|
+
milestones: milestonesParam
|
|
1980
|
+
}).accountsPartial({
|
|
1981
|
+
project: projectPda,
|
|
1982
|
+
tokenomics: tokenomicsPda,
|
|
1983
|
+
fundingRound: fundingRoundPda,
|
|
1984
|
+
roundEscrow: roundEscrowPda,
|
|
1985
|
+
roundEscrowAuthority: roundEscrowAuthorityPda,
|
|
1986
|
+
usdcMint: args.usdcMint,
|
|
1987
|
+
previousFundingRound: args.previousFundingRoundPda ?? null,
|
|
1988
|
+
founder,
|
|
1989
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1990
|
+
systemProgram: SystemProgram.programId,
|
|
1991
|
+
rent: SYSVAR_RENT_PUBKEY
|
|
1992
|
+
}).remainingAccounts(remainingAccounts).rpc();
|
|
1993
|
+
}
|
|
1994
|
+
async function investInRound(program, args, investor) {
|
|
1995
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
1996
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, args.roundNumber, program.programId);
|
|
1997
|
+
const roundEscrowPda = getRoundEscrowPDA(projectPda, args.roundNumber, program.programId);
|
|
1998
|
+
const firstRoundMilestonePda = getRoundMilestonePDA(projectPda, args.roundNumber, 0, program.programId);
|
|
1999
|
+
const [nftMint] = getRoundNftMintPDA(args.projectId, args.roundNumber, investor, args.investmentCount, program.programId);
|
|
2000
|
+
const investmentPda = getRoundInvestmentPDA(projectPda, args.roundNumber, nftMint, program.programId);
|
|
2001
|
+
const investorNftAccount = getAssociatedTokenAddressSync(nftMint, investor);
|
|
2002
|
+
const metadataAccount = getMetadataPDA(nftMint);
|
|
2003
|
+
const masterEdition = getMasterEditionPDA(nftMint);
|
|
2004
|
+
const [programAuthority] = getProgramAuthorityPDA(program.programId);
|
|
2005
|
+
return getMethods(program).investInRound({ amount: args.amount }).accountsPartial({
|
|
2006
|
+
project: projectPda,
|
|
2007
|
+
fundingRound: fundingRoundPda,
|
|
2008
|
+
firstRoundMilestone: firstRoundMilestonePda,
|
|
2009
|
+
nftMint,
|
|
2010
|
+
investment: investmentPda,
|
|
2011
|
+
investorNftAccount,
|
|
2012
|
+
metadataAccount,
|
|
2013
|
+
masterEdition,
|
|
2014
|
+
roundEscrow: roundEscrowPda,
|
|
2015
|
+
investorTokenAccount: args.investorTokenAccount,
|
|
2016
|
+
programAuthority,
|
|
2017
|
+
investor,
|
|
2018
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
2019
|
+
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
2020
|
+
systemProgram: SystemProgram.programId,
|
|
2021
|
+
rent: SYSVAR_RENT_PUBKEY,
|
|
2022
|
+
tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
|
|
2023
|
+
sysvarInstructions: SYSVAR_INSTRUCTIONS_PUBKEY
|
|
2024
|
+
}).preInstructions([
|
|
2025
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: 4e5 })
|
|
2026
|
+
]).rpc();
|
|
2027
|
+
}
|
|
2028
|
+
async function cancelRoundInvestment(program, args, investor) {
|
|
2029
|
+
const nftMintPubkey = ensurePublicKey(args.nftMint);
|
|
2030
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
2031
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, args.roundNumber, program.programId);
|
|
2032
|
+
const investmentPda = getRoundInvestmentPDA(projectPda, args.roundNumber, nftMintPubkey, program.programId);
|
|
2033
|
+
const roundEscrowPda = getRoundEscrowPDA(projectPda, args.roundNumber, program.programId);
|
|
2034
|
+
const [roundEscrowAuthorityPda] = getRoundEscrowAuthorityPDA(projectPda, args.roundNumber, program.programId);
|
|
2035
|
+
return getMethods(program).cancelRoundInvestment().accountsPartial({
|
|
2036
|
+
investor,
|
|
2037
|
+
project: projectPda,
|
|
2038
|
+
fundingRound: fundingRoundPda,
|
|
2039
|
+
investment: investmentPda,
|
|
2040
|
+
nftMint: nftMintPubkey,
|
|
2041
|
+
investorNftAccount: args.investorNftAccount,
|
|
2042
|
+
roundEscrow: roundEscrowPda,
|
|
2043
|
+
roundEscrowAuthority: roundEscrowAuthorityPda,
|
|
2044
|
+
investorUsdcAccount: args.investorUsdcAccount,
|
|
2045
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
2046
|
+
}).rpc();
|
|
2047
|
+
}
|
|
2048
|
+
async function submitRoundMilestone(program, args, founder) {
|
|
2049
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
2050
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, args.roundNumber, program.programId);
|
|
2051
|
+
const milestonePda = getRoundMilestonePDA(projectPda, args.roundNumber, args.milestoneIndex, program.programId);
|
|
2052
|
+
return getMethods(program).submitRoundMilestone().accountsPartial({
|
|
2053
|
+
founder,
|
|
2054
|
+
project: projectPda,
|
|
2055
|
+
fundingRound: fundingRoundPda,
|
|
2056
|
+
milestone: milestonePda,
|
|
2057
|
+
clock: SYSVAR_CLOCK_PUBKEY
|
|
2058
|
+
}).rpc();
|
|
2059
|
+
}
|
|
2060
|
+
async function voteOnRoundMilestone(program, args, voter) {
|
|
2061
|
+
const nftMintPubkey = ensurePublicKey(args.nftMint);
|
|
2062
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
2063
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, args.roundNumber, program.programId);
|
|
2064
|
+
const milestonePda = getRoundMilestonePDA(projectPda, args.roundNumber, args.milestoneIndex, program.programId);
|
|
2065
|
+
let investmentPda;
|
|
2066
|
+
if (args.investmentRoundNumber === 1) {
|
|
2067
|
+
investmentPda = getInvestmentPDA(projectPda, nftMintPubkey, program.programId);
|
|
2068
|
+
} else {
|
|
2069
|
+
investmentPda = getRoundInvestmentPDA(projectPda, args.investmentRoundNumber, nftMintPubkey, program.programId);
|
|
2070
|
+
}
|
|
2071
|
+
const milestone = await getAccountNamespace2(program).milestone.fetch(milestonePda);
|
|
2072
|
+
const votingRound = milestone.votingRound ?? 0;
|
|
2073
|
+
const votePda = getVotePDA(milestonePda, voter, votingRound, program.programId);
|
|
2074
|
+
const voterNftAccount = getAssociatedTokenAddressSync(
|
|
2075
|
+
nftMintPubkey,
|
|
2076
|
+
voter,
|
|
2077
|
+
false,
|
|
2078
|
+
TOKEN_PROGRAM_ID
|
|
2079
|
+
);
|
|
2080
|
+
return getMethods(program).voteOnRoundMilestone({ choice: args.choice }).accountsPartial({
|
|
2081
|
+
vote: votePda,
|
|
2082
|
+
project: projectPda,
|
|
2083
|
+
fundingRound: fundingRoundPda,
|
|
2084
|
+
milestone: milestonePda,
|
|
2085
|
+
investment: investmentPda,
|
|
2086
|
+
nftMint: nftMintPubkey,
|
|
2087
|
+
voterNftAccount,
|
|
2088
|
+
voter,
|
|
2089
|
+
systemProgram: SystemProgram.programId
|
|
2090
|
+
}).rpc();
|
|
2091
|
+
}
|
|
2092
|
+
async function finalizeRoundVoting(program, args) {
|
|
2093
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
2094
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, args.roundNumber, program.programId);
|
|
2095
|
+
const milestonePda = getRoundMilestonePDA(projectPda, args.roundNumber, args.milestoneIndex, program.programId);
|
|
2096
|
+
return getMethods(program).finalizeRoundVoting().accountsPartial({
|
|
2097
|
+
project: projectPda,
|
|
2098
|
+
fundingRound: fundingRoundPda,
|
|
2099
|
+
milestone: milestonePda,
|
|
2100
|
+
clock: SYSVAR_CLOCK_PUBKEY
|
|
2101
|
+
}).rpc();
|
|
2102
|
+
}
|
|
2103
|
+
async function claimRoundMilestoneFunds(program, args, founder) {
|
|
2104
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
2105
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, args.roundNumber, program.programId);
|
|
2106
|
+
const milestonePda = getRoundMilestonePDA(projectPda, args.roundNumber, args.milestoneIndex, program.programId);
|
|
2107
|
+
const roundEscrowPda = getRoundEscrowPDA(projectPda, args.roundNumber, program.programId);
|
|
2108
|
+
const [roundEscrowAuthorityPda] = getRoundEscrowAuthorityPDA(projectPda, args.roundNumber, program.programId);
|
|
2109
|
+
const nextMilestonePda = args.nextMilestoneDeadline.gt(new BN(0)) ? getRoundMilestonePDA(projectPda, args.roundNumber, args.milestoneIndex + 1, program.programId) : null;
|
|
2110
|
+
return getMethods(program).claimRoundMilestoneFunds({ nextMilestoneDeadline: args.nextMilestoneDeadline }).accountsPartial({
|
|
2111
|
+
project: projectPda,
|
|
2112
|
+
fundingRound: fundingRoundPda,
|
|
2113
|
+
milestone: milestonePda,
|
|
2114
|
+
founder,
|
|
2115
|
+
roundEscrow: roundEscrowPda,
|
|
2116
|
+
roundEscrowAuthority: roundEscrowAuthorityPda,
|
|
2117
|
+
founderUsdcAccount: args.founderUsdcAccount,
|
|
2118
|
+
nextMilestone: nextMilestonePda,
|
|
2119
|
+
systemProgram: SystemProgram.programId,
|
|
2120
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
2121
|
+
}).rpc();
|
|
2122
|
+
}
|
|
2123
|
+
async function claimRoundInstantTokens(program, args, investor) {
|
|
2124
|
+
const nftMintPubkey = ensurePublicKey(args.nftMint);
|
|
2125
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
2126
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, args.roundNumber, program.programId);
|
|
2127
|
+
const milestonePda = getRoundMilestonePDA(projectPda, args.roundNumber, args.milestoneIndex, program.programId);
|
|
2128
|
+
const investmentPda = getRoundInvestmentPDA(projectPda, args.roundNumber, nftMintPubkey, program.programId);
|
|
2129
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
2130
|
+
const futureRoundVaultPda = getFutureRoundVaultPDA(projectPda, program.programId);
|
|
2131
|
+
const futureRoundTokenVaultPda = getFutureRoundTokenVaultPDA(projectPda, program.programId);
|
|
2132
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
2133
|
+
const vestingPda = getRoundInvestorMilestoneVestingPDA(
|
|
2134
|
+
projectPda,
|
|
2135
|
+
args.roundNumber,
|
|
2136
|
+
args.milestoneIndex,
|
|
2137
|
+
investmentPda,
|
|
2138
|
+
program.programId
|
|
2139
|
+
);
|
|
2140
|
+
const investorNftAccount = getAssociatedTokenAddressSync(
|
|
2141
|
+
nftMintPubkey,
|
|
2142
|
+
investor,
|
|
2143
|
+
false,
|
|
2144
|
+
TOKEN_PROGRAM_ID
|
|
2145
|
+
);
|
|
2146
|
+
return getMethods(program).claimRoundInstantTokens({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
2147
|
+
investor,
|
|
2148
|
+
project: projectPda,
|
|
2149
|
+
fundingRound: fundingRoundPda,
|
|
2150
|
+
milestone: milestonePda,
|
|
2151
|
+
investment: investmentPda,
|
|
2152
|
+
tokenVault: tokenVaultPda,
|
|
2153
|
+
futureRoundVault: futureRoundVaultPda,
|
|
2154
|
+
vesting: vestingPda,
|
|
2155
|
+
nftMint: nftMintPubkey,
|
|
2156
|
+
investorNftAccount,
|
|
2157
|
+
futureRoundTokenVault: futureRoundTokenVaultPda,
|
|
2158
|
+
investorTokenAccount: args.investorTokenAccount,
|
|
2159
|
+
vaultAuthority: vaultAuthorityPda,
|
|
2160
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
2161
|
+
systemProgram: SystemProgram.programId
|
|
2162
|
+
}).rpc();
|
|
2163
|
+
}
|
|
2164
|
+
async function claimRoundVestedTokens(program, args, investor) {
|
|
2165
|
+
const nftMintPubkey = ensurePublicKey(args.nftMint);
|
|
2166
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
2167
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, args.roundNumber, program.programId);
|
|
2168
|
+
const milestonePda = getRoundMilestonePDA(projectPda, args.roundNumber, args.milestoneIndex, program.programId);
|
|
2169
|
+
const investmentPda = getRoundInvestmentPDA(projectPda, args.roundNumber, nftMintPubkey, program.programId);
|
|
2170
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
2171
|
+
const futureRoundVaultPda = getFutureRoundVaultPDA(projectPda, program.programId);
|
|
2172
|
+
const futureRoundTokenVaultPda = getFutureRoundTokenVaultPDA(projectPda, program.programId);
|
|
2173
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
2174
|
+
const vestingPda = getRoundInvestorMilestoneVestingPDA(
|
|
2175
|
+
projectPda,
|
|
2176
|
+
args.roundNumber,
|
|
2177
|
+
args.milestoneIndex,
|
|
2178
|
+
investmentPda,
|
|
2179
|
+
program.programId
|
|
2180
|
+
);
|
|
2181
|
+
const investorNftAccount = getAssociatedTokenAddressSync(
|
|
2182
|
+
nftMintPubkey,
|
|
2183
|
+
investor,
|
|
2184
|
+
false,
|
|
2185
|
+
TOKEN_PROGRAM_ID
|
|
2186
|
+
);
|
|
2187
|
+
return getMethods(program).claimRoundVestedTokens({ milestoneIndex: args.milestoneIndex }).accountsPartial({
|
|
2188
|
+
investor,
|
|
2189
|
+
project: projectPda,
|
|
2190
|
+
fundingRound: fundingRoundPda,
|
|
2191
|
+
milestone: milestonePda,
|
|
2192
|
+
investment: investmentPda,
|
|
2193
|
+
tokenVault: tokenVaultPda,
|
|
2194
|
+
futureRoundVault: futureRoundVaultPda,
|
|
2195
|
+
vesting: vestingPda,
|
|
2196
|
+
nftMint: nftMintPubkey,
|
|
2197
|
+
investorNftAccount,
|
|
2198
|
+
futureRoundTokenVault: futureRoundTokenVaultPda,
|
|
2199
|
+
investorTokenAccount: args.investorTokenAccount,
|
|
2200
|
+
vaultAuthority: vaultAuthorityPda,
|
|
2201
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
2202
|
+
}).rpc();
|
|
2203
|
+
}
|
|
2204
|
+
async function claimRoundEarlyTokens(program, args, investor) {
|
|
2205
|
+
const nftMintPubkey = ensurePublicKey(args.nftMint);
|
|
2206
|
+
const projectPda = getProjectPDA(args.projectId, program.programId);
|
|
2207
|
+
const fundingRoundPda = getFundingRoundPDA(projectPda, args.roundNumber, program.programId);
|
|
2208
|
+
const investmentPda = getRoundInvestmentPDA(projectPda, args.roundNumber, nftMintPubkey, program.programId);
|
|
2209
|
+
const tokenVaultPda = getTokenVaultPDA(projectPda, program.programId);
|
|
2210
|
+
const futureRoundVaultPda = getFutureRoundVaultPDA(projectPda, program.programId);
|
|
2211
|
+
const futureRoundTokenVaultPda = getFutureRoundTokenVaultPDA(projectPda, program.programId);
|
|
2212
|
+
const vaultAuthorityPda = getVaultAuthorityPDA(projectPda, program.programId);
|
|
2213
|
+
const investorNftAccount = getAssociatedTokenAddressSync(
|
|
2214
|
+
nftMintPubkey,
|
|
2215
|
+
investor,
|
|
2216
|
+
false,
|
|
2217
|
+
TOKEN_PROGRAM_ID
|
|
2218
|
+
);
|
|
2219
|
+
return getMethods(program).claimRoundEarlyTokens().accountsPartial({
|
|
2220
|
+
investor,
|
|
2221
|
+
project: projectPda,
|
|
2222
|
+
fundingRound: fundingRoundPda,
|
|
2223
|
+
investment: investmentPda,
|
|
2224
|
+
tokenVault: tokenVaultPda,
|
|
2225
|
+
futureRoundVault: futureRoundVaultPda,
|
|
2226
|
+
nftMint: nftMintPubkey,
|
|
2227
|
+
investorNftAccount,
|
|
2228
|
+
futureRoundTokenVault: futureRoundTokenVaultPda,
|
|
2229
|
+
investorTokenAccount: args.investorTokenAccount,
|
|
2230
|
+
vaultAuthority: vaultAuthorityPda,
|
|
2231
|
+
tokenProgram: TOKEN_PROGRAM_ID
|
|
2232
|
+
}).rpc();
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
// src/client.ts
|
|
2236
|
+
var RaiseClient = class _RaiseClient {
|
|
2237
|
+
/**
|
|
2238
|
+
* Create a new RaiseClient
|
|
2239
|
+
*
|
|
2240
|
+
* @param program - Anchor program instance
|
|
2241
|
+
* @param provider - Anchor provider
|
|
2242
|
+
*/
|
|
2243
|
+
constructor(program, provider) {
|
|
2244
|
+
this.program = program;
|
|
2245
|
+
this.provider = provider;
|
|
2246
|
+
}
|
|
2247
|
+
/**
|
|
2248
|
+
* Load a new RaiseClient instance
|
|
2249
|
+
*
|
|
2250
|
+
* @param connection - Solana connection
|
|
2251
|
+
* @param wallet - Wallet instance
|
|
2252
|
+
* @param programId - Optional program ID override
|
|
2253
|
+
* @returns Initialized RaiseClient
|
|
2254
|
+
*
|
|
2255
|
+
* @example
|
|
2256
|
+
* ```typescript
|
|
2257
|
+
* const client = RaiseClient.load(connection, wallet);
|
|
2258
|
+
* ```
|
|
2259
|
+
*/
|
|
2260
|
+
static load(_connection, _wallet, _programId) {
|
|
2261
|
+
throw new Error(
|
|
2262
|
+
"RaiseClient.load requires IDL. Use RaiseClient.fromProgram instead, or ensure the IDL is bundled with your application."
|
|
2263
|
+
);
|
|
2264
|
+
}
|
|
2265
|
+
/**
|
|
2266
|
+
* Create client from an existing program instance
|
|
2267
|
+
*
|
|
2268
|
+
* @param program - Anchor program instance
|
|
2269
|
+
* @returns Initialized RaiseClient
|
|
2270
|
+
*
|
|
2271
|
+
* @example
|
|
2272
|
+
* ```typescript
|
|
2273
|
+
* import idl from './idl/raise.json';
|
|
2274
|
+
*
|
|
2275
|
+
* const provider = new AnchorProvider(connection, wallet, {});
|
|
2276
|
+
* const program = new Program(idl, provider);
|
|
2277
|
+
* const client = RaiseClient.fromProgram(program);
|
|
2278
|
+
* ```
|
|
2279
|
+
*/
|
|
2280
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2281
|
+
static fromProgram(program) {
|
|
2282
|
+
const provider = program.provider;
|
|
2283
|
+
return new _RaiseClient(program, provider);
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* Get the program ID
|
|
2287
|
+
*/
|
|
2288
|
+
get programId() {
|
|
2289
|
+
return this.program.programId;
|
|
2290
|
+
}
|
|
2291
|
+
/**
|
|
2292
|
+
* Get the connected wallet public key
|
|
2293
|
+
*/
|
|
2294
|
+
get walletPublicKey() {
|
|
2295
|
+
return this.provider.wallet.publicKey;
|
|
2296
|
+
}
|
|
2297
|
+
// ===========================================================================
|
|
1191
2298
|
// PDA Helpers
|
|
1192
2299
|
// ===========================================================================
|
|
1193
2300
|
getProjectPDA(projectId) {
|
|
@@ -1214,381 +2321,1166 @@ var RaiseClient = class _RaiseClient {
|
|
|
1214
2321
|
getTgeEscrowVaultPDA(projectPda) {
|
|
1215
2322
|
return getTgeEscrowVaultPDA(projectPda, this.programId);
|
|
1216
2323
|
}
|
|
1217
|
-
getAdminConfigPDA() {
|
|
1218
|
-
return getAdminConfigPDA(this.programId);
|
|
2324
|
+
getAdminConfigPDA() {
|
|
2325
|
+
return getAdminConfigPDA(this.programId);
|
|
2326
|
+
}
|
|
2327
|
+
getAllocationProposalPDA(projectPda, proposalIndex) {
|
|
2328
|
+
return getAllocationProposalPDA(projectPda, proposalIndex, this.programId);
|
|
2329
|
+
}
|
|
2330
|
+
getAllocationVotePDA(proposalPda, nftMint) {
|
|
2331
|
+
return getAllocationVotePDA(proposalPda, nftMint, this.programId);
|
|
2332
|
+
}
|
|
2333
|
+
getSubAllocationVestingPDA(projectPda, subAllocationId) {
|
|
2334
|
+
return getSubAllocationVestingPDA(projectPda, subAllocationId, this.programId);
|
|
2335
|
+
}
|
|
2336
|
+
getTokenomicsPDA(projectPda) {
|
|
2337
|
+
return getTokenomicsPDA(projectPda, this.programId);
|
|
2338
|
+
}
|
|
2339
|
+
// Per-Milestone Vesting PDAs
|
|
2340
|
+
getInvestorMilestoneVestingPDA(projectPda, milestoneIndex, investmentPda) {
|
|
2341
|
+
return getInvestorMilestoneVestingPDA(projectPda, milestoneIndex, investmentPda, this.programId);
|
|
2342
|
+
}
|
|
2343
|
+
getFounderMilestoneVestingPDA(projectPda, milestoneIndex) {
|
|
2344
|
+
return getFounderMilestoneVestingPDA(projectPda, milestoneIndex, this.programId);
|
|
2345
|
+
}
|
|
2346
|
+
// ===========================================================================
|
|
2347
|
+
// Account Fetchers
|
|
2348
|
+
// ===========================================================================
|
|
2349
|
+
async fetchProject(projectId) {
|
|
2350
|
+
return fetchProject(this.program, projectId);
|
|
2351
|
+
}
|
|
2352
|
+
async fetchMilestone(projectId, milestoneIndex) {
|
|
2353
|
+
return fetchMilestone(this.program, projectId, milestoneIndex);
|
|
2354
|
+
}
|
|
2355
|
+
async fetchAllMilestones(projectId) {
|
|
2356
|
+
return fetchAllMilestones(this.program, projectId);
|
|
2357
|
+
}
|
|
2358
|
+
async fetchInvestment(projectId, nftMint) {
|
|
2359
|
+
return fetchInvestment(this.program, projectId, nftMint);
|
|
2360
|
+
}
|
|
2361
|
+
async fetchAllInvestments(projectId) {
|
|
2362
|
+
return fetchAllInvestments(this.program, projectId);
|
|
2363
|
+
}
|
|
2364
|
+
async fetchVote(projectId, milestoneIndex, voterKey, votingRound) {
|
|
2365
|
+
return fetchVote(this.program, projectId, milestoneIndex, voterKey, votingRound);
|
|
2366
|
+
}
|
|
2367
|
+
async fetchAllVotes(projectId, milestoneIndex) {
|
|
2368
|
+
return fetchAllVotes(this.program, projectId, milestoneIndex);
|
|
2369
|
+
}
|
|
2370
|
+
async fetchPivotProposal(projectId) {
|
|
2371
|
+
return fetchPivotProposal(this.program, projectId);
|
|
2372
|
+
}
|
|
2373
|
+
async fetchTgeEscrow(projectId) {
|
|
2374
|
+
return fetchTgeEscrow(this.program, projectId);
|
|
2375
|
+
}
|
|
2376
|
+
async fetchAdminConfig() {
|
|
2377
|
+
return fetchAdminConfig(this.program);
|
|
2378
|
+
}
|
|
2379
|
+
async fetchTokenVault(projectId) {
|
|
2380
|
+
return fetchTokenVault(this.program, projectId);
|
|
2381
|
+
}
|
|
2382
|
+
async fetchTokenomics(projectId) {
|
|
2383
|
+
return fetchTokenomics(this.program, projectId);
|
|
2384
|
+
}
|
|
2385
|
+
async fetchAllocationProposal(projectId, proposalIndex) {
|
|
2386
|
+
return fetchAllocationProposal(this.program, projectId, proposalIndex);
|
|
2387
|
+
}
|
|
2388
|
+
async fetchAllAllocationProposals(projectId) {
|
|
2389
|
+
return fetchAllAllocationProposals(this.program, projectId);
|
|
2390
|
+
}
|
|
2391
|
+
async fetchAllocationVote(projectId, proposalIndex, nftMint) {
|
|
2392
|
+
return fetchAllocationVote(this.program, projectId, proposalIndex, nftMint);
|
|
2393
|
+
}
|
|
2394
|
+
async fetchSubAllocationVesting(projectId, subAllocationId) {
|
|
2395
|
+
return fetchSubAllocationVesting(this.program, projectId, subAllocationId);
|
|
2396
|
+
}
|
|
2397
|
+
async fetchInvestorMilestoneVesting(projectId, milestoneIndex, nftMint) {
|
|
2398
|
+
return fetchInvestorMilestoneVesting(this.program, projectId, milestoneIndex, nftMint);
|
|
2399
|
+
}
|
|
2400
|
+
async fetchFounderMilestoneVesting(projectId, milestoneIndex) {
|
|
2401
|
+
return fetchFounderMilestoneVesting(this.program, projectId, milestoneIndex);
|
|
2402
|
+
}
|
|
2403
|
+
// ===========================================================================
|
|
2404
|
+
// Admin Instructions
|
|
2405
|
+
// ===========================================================================
|
|
2406
|
+
async initializeAdmin(admin) {
|
|
2407
|
+
return initializeAdmin(
|
|
2408
|
+
this.program,
|
|
2409
|
+
admin,
|
|
2410
|
+
this.walletPublicKey
|
|
2411
|
+
);
|
|
2412
|
+
}
|
|
2413
|
+
async transferAdmin(newAdmin, adminKeypair) {
|
|
2414
|
+
return transferAdmin(
|
|
2415
|
+
this.program,
|
|
2416
|
+
adminKeypair,
|
|
2417
|
+
newAdmin
|
|
2418
|
+
);
|
|
2419
|
+
}
|
|
2420
|
+
async acceptAdmin() {
|
|
2421
|
+
return acceptAdmin(
|
|
2422
|
+
this.program,
|
|
2423
|
+
this.walletPublicKey
|
|
2424
|
+
);
|
|
2425
|
+
}
|
|
2426
|
+
// ===========================================================================
|
|
2427
|
+
// Project Instructions
|
|
2428
|
+
// ===========================================================================
|
|
2429
|
+
async initializeProject(args) {
|
|
2430
|
+
return initializeProject(
|
|
2431
|
+
this.program,
|
|
2432
|
+
args,
|
|
2433
|
+
this.walletPublicKey
|
|
2434
|
+
);
|
|
2435
|
+
}
|
|
2436
|
+
async submitForApproval(projectId) {
|
|
2437
|
+
return submitForApproval(
|
|
2438
|
+
this.program,
|
|
2439
|
+
projectId,
|
|
2440
|
+
this.walletPublicKey
|
|
2441
|
+
);
|
|
2442
|
+
}
|
|
2443
|
+
async approveProject(args, adminKeypair) {
|
|
2444
|
+
return approveProject(
|
|
2445
|
+
this.program,
|
|
2446
|
+
args,
|
|
2447
|
+
adminKeypair
|
|
2448
|
+
);
|
|
2449
|
+
}
|
|
2450
|
+
// ===========================================================================
|
|
2451
|
+
// Milestone Instructions
|
|
2452
|
+
// ===========================================================================
|
|
2453
|
+
async createMilestone(args) {
|
|
2454
|
+
return createMilestone(
|
|
2455
|
+
this.program,
|
|
2456
|
+
args,
|
|
2457
|
+
this.walletPublicKey
|
|
2458
|
+
);
|
|
2459
|
+
}
|
|
2460
|
+
async submitMilestone(projectId, milestoneIndex) {
|
|
2461
|
+
return submitMilestone(
|
|
2462
|
+
this.program,
|
|
2463
|
+
projectId,
|
|
2464
|
+
milestoneIndex,
|
|
2465
|
+
this.walletPublicKey
|
|
2466
|
+
);
|
|
2467
|
+
}
|
|
2468
|
+
async voteOnMilestone(args) {
|
|
2469
|
+
return voteOnMilestone(
|
|
2470
|
+
this.program,
|
|
2471
|
+
args,
|
|
2472
|
+
this.walletPublicKey
|
|
2473
|
+
);
|
|
2474
|
+
}
|
|
2475
|
+
async finalizeVoting(projectId, milestoneIndex) {
|
|
2476
|
+
return finalizeVoting(
|
|
2477
|
+
this.program,
|
|
2478
|
+
projectId,
|
|
2479
|
+
milestoneIndex
|
|
2480
|
+
);
|
|
2481
|
+
}
|
|
2482
|
+
/**
|
|
2483
|
+
* Claim milestone funds (ZTM v2.0)
|
|
2484
|
+
* - Regular milestones: Full payout to founder
|
|
2485
|
+
* - Final milestone: LP USDC reserved for PCL, triggers MAE
|
|
2486
|
+
*
|
|
2487
|
+
* @param nextMilestoneDeadline - Deadline for next milestone (required for non-final milestones)
|
|
2488
|
+
* Set to BN(0) for final milestone claims (no next milestone exists)
|
|
2489
|
+
*/
|
|
2490
|
+
async claimMilestoneFunds(args) {
|
|
2491
|
+
return claimMilestoneFunds(
|
|
2492
|
+
this.program,
|
|
2493
|
+
args,
|
|
2494
|
+
this.walletPublicKey
|
|
2495
|
+
);
|
|
2496
|
+
}
|
|
2497
|
+
/**
|
|
2498
|
+
* Resubmit a failed milestone for rework (Failed → InProgress)
|
|
2499
|
+
*
|
|
2500
|
+
* Allows founders to iterate on failed milestones. Clears voting state
|
|
2501
|
+
* for a fresh voting cycle. consecutive_failures is NOT reset.
|
|
2502
|
+
*/
|
|
2503
|
+
async resubmitMilestone(args) {
|
|
2504
|
+
return resubmitMilestone(
|
|
2505
|
+
this.program,
|
|
2506
|
+
args,
|
|
2507
|
+
this.walletPublicKey
|
|
2508
|
+
);
|
|
2509
|
+
}
|
|
2510
|
+
/**
|
|
2511
|
+
* Set milestone deadline for founder to commit submission date
|
|
2512
|
+
*
|
|
2513
|
+
* Founders must set deadlines for milestones to provide visibility to investors.
|
|
2514
|
+
* Deadline must be at least 7 days from now and at most 1 year from now.
|
|
2515
|
+
*/
|
|
2516
|
+
async setMilestoneDeadline(args) {
|
|
2517
|
+
return setMilestoneDeadline(
|
|
2518
|
+
this.program,
|
|
2519
|
+
args,
|
|
2520
|
+
this.walletPublicKey
|
|
2521
|
+
);
|
|
2522
|
+
}
|
|
2523
|
+
/**
|
|
2524
|
+
* Extend milestone deadline (max 3 extensions per milestone)
|
|
2525
|
+
*
|
|
2526
|
+
* Founders can extend a deadline up to 3 times before it passes.
|
|
2527
|
+
* Must be called BEFORE the current deadline passes.
|
|
2528
|
+
*/
|
|
2529
|
+
async extendMilestoneDeadline(args) {
|
|
2530
|
+
return extendMilestoneDeadline(
|
|
2531
|
+
this.program,
|
|
2532
|
+
args,
|
|
2533
|
+
this.walletPublicKey
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
// ===========================================================================
|
|
2537
|
+
// Investment Instructions
|
|
2538
|
+
// ===========================================================================
|
|
2539
|
+
async invest(args) {
|
|
2540
|
+
return invest(
|
|
2541
|
+
this.program,
|
|
2542
|
+
args,
|
|
2543
|
+
this.walletPublicKey
|
|
2544
|
+
);
|
|
2545
|
+
}
|
|
2546
|
+
async cancelInvestment(args) {
|
|
2547
|
+
return cancelInvestment(
|
|
2548
|
+
this.program,
|
|
2549
|
+
args,
|
|
2550
|
+
this.walletPublicKey
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
// ===========================================================================
|
|
2554
|
+
// Pivot Instructions
|
|
2555
|
+
// ===========================================================================
|
|
2556
|
+
async proposePivot(args) {
|
|
2557
|
+
return proposePivot(
|
|
2558
|
+
this.program,
|
|
2559
|
+
args,
|
|
2560
|
+
this.walletPublicKey
|
|
2561
|
+
);
|
|
2562
|
+
}
|
|
2563
|
+
async approvePivot(projectId, adminKeypair) {
|
|
2564
|
+
return approvePivot(
|
|
2565
|
+
this.program,
|
|
2566
|
+
projectId,
|
|
2567
|
+
adminKeypair
|
|
2568
|
+
);
|
|
2569
|
+
}
|
|
2570
|
+
async withdrawFromPivot(args) {
|
|
2571
|
+
return withdrawFromPivot(
|
|
2572
|
+
this.program,
|
|
2573
|
+
args,
|
|
2574
|
+
this.walletPublicKey
|
|
2575
|
+
);
|
|
2576
|
+
}
|
|
2577
|
+
async finalizePivot(args) {
|
|
2578
|
+
return finalizePivot(
|
|
2579
|
+
this.program,
|
|
2580
|
+
args,
|
|
2581
|
+
this.walletPublicKey
|
|
2582
|
+
);
|
|
1219
2583
|
}
|
|
1220
2584
|
// ===========================================================================
|
|
1221
|
-
//
|
|
2585
|
+
// TGE Instructions
|
|
1222
2586
|
// ===========================================================================
|
|
1223
|
-
async
|
|
1224
|
-
return
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
async fetchAllMilestones(projectId) {
|
|
1230
|
-
return fetchAllMilestones(this.program, projectId);
|
|
2587
|
+
async setTgeDate(args) {
|
|
2588
|
+
return setTgeDate(
|
|
2589
|
+
this.program,
|
|
2590
|
+
args,
|
|
2591
|
+
this.walletPublicKey
|
|
2592
|
+
);
|
|
1231
2593
|
}
|
|
1232
|
-
async
|
|
1233
|
-
return
|
|
2594
|
+
async depositTokens(args) {
|
|
2595
|
+
return depositTokens(
|
|
2596
|
+
this.program,
|
|
2597
|
+
args,
|
|
2598
|
+
this.walletPublicKey
|
|
2599
|
+
);
|
|
1234
2600
|
}
|
|
1235
|
-
async
|
|
1236
|
-
return
|
|
2601
|
+
async claimTokens(args) {
|
|
2602
|
+
return claimTokens(
|
|
2603
|
+
this.program,
|
|
2604
|
+
args,
|
|
2605
|
+
this.walletPublicKey
|
|
2606
|
+
);
|
|
1237
2607
|
}
|
|
1238
|
-
async
|
|
1239
|
-
return
|
|
2608
|
+
async reportScam(args) {
|
|
2609
|
+
return reportScam(
|
|
2610
|
+
this.program,
|
|
2611
|
+
args,
|
|
2612
|
+
this.walletPublicKey
|
|
2613
|
+
);
|
|
1240
2614
|
}
|
|
1241
|
-
async
|
|
1242
|
-
return
|
|
2615
|
+
async releaseHoldback(args) {
|
|
2616
|
+
return releaseHoldback(
|
|
2617
|
+
this.program,
|
|
2618
|
+
args
|
|
2619
|
+
);
|
|
1243
2620
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
2621
|
+
// ===========================================================================
|
|
2622
|
+
// ZTM v2.0 Token Distribution Instructions
|
|
2623
|
+
// ===========================================================================
|
|
2624
|
+
/**
|
|
2625
|
+
* Claim investor tokens from a passed milestone (whitepaper: manual claim model)
|
|
2626
|
+
*
|
|
2627
|
+
* ZTM v2.0: Per whitepaper, investors manually claim their tokens after a milestone passes.
|
|
2628
|
+
* This replaces the batch distribution model with investor-initiated per-NFT claims.
|
|
2629
|
+
*/
|
|
2630
|
+
async claimInvestorTokens(args) {
|
|
2631
|
+
return claimInvestorTokens(
|
|
2632
|
+
this.program,
|
|
2633
|
+
args,
|
|
2634
|
+
this.walletPublicKey
|
|
2635
|
+
);
|
|
1246
2636
|
}
|
|
1247
|
-
|
|
1248
|
-
|
|
2637
|
+
/**
|
|
2638
|
+
* Distribute tokens to NFT holders for a milestone
|
|
2639
|
+
*
|
|
2640
|
+
* ZTM v2.0: Called by cranker after finalize_voting sets distribution_pending = true.
|
|
2641
|
+
* Processes batch of investments, transferring unlocked tokens to NFT holders.
|
|
2642
|
+
* Max batch size: 10 investments per call.
|
|
2643
|
+
*
|
|
2644
|
+
* @deprecated Use claimInvestorTokens instead (whitepaper manual claim model)
|
|
2645
|
+
*/
|
|
2646
|
+
async distributeTokens(args) {
|
|
2647
|
+
return distributeTokens(
|
|
2648
|
+
this.program,
|
|
2649
|
+
args,
|
|
2650
|
+
this.walletPublicKey
|
|
2651
|
+
);
|
|
1249
2652
|
}
|
|
1250
|
-
|
|
1251
|
-
|
|
2653
|
+
/**
|
|
2654
|
+
* Complete token distribution for a milestone
|
|
2655
|
+
*
|
|
2656
|
+
* ZTM v2.0: Marks distribution as complete after all batches have been processed.
|
|
2657
|
+
* Permissionless - anyone can call this to finalize a distribution.
|
|
2658
|
+
*/
|
|
2659
|
+
async completeDistribution(args) {
|
|
2660
|
+
return completeDistribution(
|
|
2661
|
+
this.program,
|
|
2662
|
+
args,
|
|
2663
|
+
this.walletPublicKey
|
|
2664
|
+
);
|
|
1252
2665
|
}
|
|
1253
2666
|
// ===========================================================================
|
|
1254
|
-
//
|
|
2667
|
+
// ZTM v2.0: Founder Vesting Instructions
|
|
1255
2668
|
// ===========================================================================
|
|
1256
|
-
|
|
1257
|
-
|
|
2669
|
+
/**
|
|
2670
|
+
* Initialize founder vesting after MAE (Market Access Event)
|
|
2671
|
+
*
|
|
2672
|
+
* ZTM v2.0: Creates FounderVesting PDA with vesting schedule from Tokenomics.
|
|
2673
|
+
* Must be called after project reaches Completed state (all milestones done).
|
|
2674
|
+
* Permissionless - anyone can pay to initialize.
|
|
2675
|
+
*/
|
|
2676
|
+
async initializeFounderVesting(args) {
|
|
2677
|
+
return initializeFounderVesting(
|
|
1258
2678
|
this.program,
|
|
1259
|
-
|
|
2679
|
+
args,
|
|
1260
2680
|
this.walletPublicKey
|
|
1261
2681
|
);
|
|
1262
2682
|
}
|
|
1263
|
-
|
|
1264
|
-
|
|
2683
|
+
/**
|
|
2684
|
+
* Claim vested tokens from founder vault
|
|
2685
|
+
*
|
|
2686
|
+
* ZTM v2.0: Founder claims tokens based on linear vesting schedule.
|
|
2687
|
+
* Requires cliff period to pass before any tokens can be claimed.
|
|
2688
|
+
*/
|
|
2689
|
+
async claimVestedTokens(args) {
|
|
2690
|
+
return claimVestedTokens(
|
|
1265
2691
|
this.program,
|
|
1266
|
-
|
|
1267
|
-
|
|
2692
|
+
args,
|
|
2693
|
+
this.walletPublicKey
|
|
1268
2694
|
);
|
|
1269
2695
|
}
|
|
1270
|
-
|
|
1271
|
-
|
|
2696
|
+
// ===========================================================================
|
|
2697
|
+
// ZTM v2.0: Circuit Breaker Instructions
|
|
2698
|
+
// ===========================================================================
|
|
2699
|
+
/**
|
|
2700
|
+
* Force complete a stuck distribution (admin only)
|
|
2701
|
+
*
|
|
2702
|
+
* ZTM v2.0: Circuit breaker for when token distribution is stuck for >7 days.
|
|
2703
|
+
* Marks distribution as complete so project can continue.
|
|
2704
|
+
* Affected investors can use claimMissedUnlock to get their tokens.
|
|
2705
|
+
*/
|
|
2706
|
+
async forceCompleteDistribution(args, adminKeypair) {
|
|
2707
|
+
return forceCompleteDistribution(
|
|
2708
|
+
this.program,
|
|
2709
|
+
args,
|
|
2710
|
+
adminKeypair
|
|
2711
|
+
);
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Claim missed token unlock after force-complete distribution
|
|
2715
|
+
*
|
|
2716
|
+
* ZTM v2.0: Allows investors to claim tokens they missed during a stuck
|
|
2717
|
+
* distribution that was force-completed by admin.
|
|
2718
|
+
*/
|
|
2719
|
+
async claimMissedUnlock(args) {
|
|
2720
|
+
return claimMissedUnlock(
|
|
1272
2721
|
this.program,
|
|
2722
|
+
args,
|
|
1273
2723
|
this.walletPublicKey
|
|
1274
2724
|
);
|
|
1275
2725
|
}
|
|
1276
2726
|
// ===========================================================================
|
|
1277
|
-
//
|
|
2727
|
+
// Early Token Release Instructions
|
|
1278
2728
|
// ===========================================================================
|
|
1279
|
-
|
|
1280
|
-
|
|
2729
|
+
/**
|
|
2730
|
+
* Claim early tokens as an investor (5% of token allocation)
|
|
2731
|
+
*
|
|
2732
|
+
* Early Token Release: Investors can claim 5% of their token allocation
|
|
2733
|
+
* 24 hours after investing. These tokens are fully liquid immediately.
|
|
2734
|
+
*
|
|
2735
|
+
* Prerequisites:
|
|
2736
|
+
* - 24h cooling period must have passed since investment
|
|
2737
|
+
* - Investment must not have already claimed early tokens
|
|
2738
|
+
* - Investment must have active voting rights
|
|
2739
|
+
*/
|
|
2740
|
+
async claimEarlyTokens(args) {
|
|
2741
|
+
return claimEarlyTokens(
|
|
1281
2742
|
this.program,
|
|
1282
2743
|
args,
|
|
1283
2744
|
this.walletPublicKey
|
|
1284
2745
|
);
|
|
1285
2746
|
}
|
|
1286
|
-
|
|
1287
|
-
|
|
2747
|
+
/**
|
|
2748
|
+
* Claim early tokens as a founder (5% of founder allocation)
|
|
2749
|
+
*
|
|
2750
|
+
* Early Token Release: Founders can claim 5% of their token allocation
|
|
2751
|
+
* when the project becomes Funded. These tokens are fully liquid immediately.
|
|
2752
|
+
*
|
|
2753
|
+
* Prerequisites:
|
|
2754
|
+
* - Project must be in Funded, InProgress, or Completed state
|
|
2755
|
+
* - Founder must not have already claimed early tokens
|
|
2756
|
+
*/
|
|
2757
|
+
async claimFounderEarlyTokens(args) {
|
|
2758
|
+
return claimFounderEarlyTokens(
|
|
1288
2759
|
this.program,
|
|
1289
|
-
|
|
2760
|
+
args,
|
|
1290
2761
|
this.walletPublicKey
|
|
1291
2762
|
);
|
|
1292
2763
|
}
|
|
1293
|
-
|
|
1294
|
-
|
|
2764
|
+
/**
|
|
2765
|
+
* Claim founder milestone-based tokens for a specific milestone
|
|
2766
|
+
*
|
|
2767
|
+
* Early Token Release: Founders can claim their milestone-based portion
|
|
2768
|
+
* (default 47.5% of founder allocation) when milestones are unlocked.
|
|
2769
|
+
*
|
|
2770
|
+
* Prerequisites:
|
|
2771
|
+
* - Milestone must be in Unlocked state
|
|
2772
|
+
* - Founder must not have already claimed tokens for this milestone
|
|
2773
|
+
*/
|
|
2774
|
+
async claimFounderMilestoneTokens(args) {
|
|
2775
|
+
return claimFounderMilestoneTokens(
|
|
1295
2776
|
this.program,
|
|
1296
2777
|
args,
|
|
1297
|
-
|
|
2778
|
+
this.walletPublicKey
|
|
1298
2779
|
);
|
|
1299
2780
|
}
|
|
1300
2781
|
// ===========================================================================
|
|
1301
|
-
// Milestone Instructions
|
|
2782
|
+
// Per-Milestone Vesting Instructions (add-per-milestone-vesting)
|
|
1302
2783
|
// ===========================================================================
|
|
1303
|
-
|
|
1304
|
-
|
|
2784
|
+
/**
|
|
2785
|
+
* Claim instant tokens for a passed milestone (investor)
|
|
2786
|
+
*
|
|
2787
|
+
* Per-milestone vesting: Investors claim the instant portion (e.g., 5-50%)
|
|
2788
|
+
* immediately when a milestone passes. Creates vesting PDA on first claim.
|
|
2789
|
+
*
|
|
2790
|
+
* @param milestoneIndex - The milestone index to claim tokens from
|
|
2791
|
+
* @param nftMint - The NFT mint proving investment ownership
|
|
2792
|
+
* @param investorTokenAccount - Investor's token account to receive claimed tokens
|
|
2793
|
+
*/
|
|
2794
|
+
async claimMilestoneInstantTokens(args) {
|
|
2795
|
+
return claimMilestoneInstantTokens(
|
|
1305
2796
|
this.program,
|
|
1306
2797
|
args,
|
|
1307
2798
|
this.walletPublicKey
|
|
1308
2799
|
);
|
|
1309
2800
|
}
|
|
1310
|
-
|
|
1311
|
-
|
|
2801
|
+
/**
|
|
2802
|
+
* Claim vested tokens for a milestone after cliff period (investor)
|
|
2803
|
+
*
|
|
2804
|
+
* Per-milestone vesting: Investors claim vested tokens linearly after
|
|
2805
|
+
* the cliff period passes. Must have already claimed instant tokens
|
|
2806
|
+
* to initialize the vesting PDA.
|
|
2807
|
+
*
|
|
2808
|
+
* @param milestoneIndex - The milestone index to claim vested tokens from
|
|
2809
|
+
* @param nftMint - The NFT mint proving investment ownership
|
|
2810
|
+
* @param investorTokenAccount - Investor's token account to receive claimed tokens
|
|
2811
|
+
*/
|
|
2812
|
+
async claimMilestoneVestedTokens(args) {
|
|
2813
|
+
return claimMilestoneVestedTokens(
|
|
1312
2814
|
this.program,
|
|
1313
|
-
|
|
1314
|
-
milestoneIndex,
|
|
2815
|
+
args,
|
|
1315
2816
|
this.walletPublicKey
|
|
1316
2817
|
);
|
|
1317
2818
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
2819
|
+
/**
|
|
2820
|
+
* Claim instant tokens for a passed milestone (founder)
|
|
2821
|
+
*
|
|
2822
|
+
* Per-milestone vesting: Founders claim the instant portion (e.g., 5-50%)
|
|
2823
|
+
* of their milestone-based allocation when a milestone passes.
|
|
2824
|
+
*
|
|
2825
|
+
* @param milestoneIndex - The milestone index to claim tokens from
|
|
2826
|
+
* @param founderTokenAccount - Founder's token account to receive claimed tokens
|
|
2827
|
+
*/
|
|
2828
|
+
async claimFounderMsInstantTokens(args) {
|
|
2829
|
+
return claimFounderMsInstantTokens(
|
|
1320
2830
|
this.program,
|
|
1321
2831
|
args,
|
|
1322
2832
|
this.walletPublicKey
|
|
1323
2833
|
);
|
|
1324
2834
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
2835
|
+
/**
|
|
2836
|
+
* Claim vested tokens for a milestone after cliff period (founder)
|
|
2837
|
+
*
|
|
2838
|
+
* Per-milestone vesting: Founders claim vested tokens linearly after
|
|
2839
|
+
* the cliff period passes. Must have already claimed instant tokens
|
|
2840
|
+
* to initialize the vesting PDA.
|
|
2841
|
+
*
|
|
2842
|
+
* @param milestoneIndex - The milestone index to claim vested tokens from
|
|
2843
|
+
* @param founderTokenAccount - Founder's token account to receive claimed tokens
|
|
2844
|
+
*/
|
|
2845
|
+
async claimFounderMsVestedTokens(args) {
|
|
2846
|
+
return claimFounderMsVestedTokens(
|
|
2847
|
+
this.program,
|
|
2848
|
+
args,
|
|
2849
|
+
this.walletPublicKey
|
|
2850
|
+
);
|
|
2851
|
+
}
|
|
2852
|
+
// ===========================================================================
|
|
2853
|
+
// Abandonment Instructions
|
|
2854
|
+
// ===========================================================================
|
|
2855
|
+
async checkAbandonment(projectId, milestoneIndex = 0) {
|
|
2856
|
+
return checkAbandonment(
|
|
1327
2857
|
this.program,
|
|
1328
2858
|
projectId,
|
|
1329
2859
|
milestoneIndex
|
|
1330
2860
|
);
|
|
1331
2861
|
}
|
|
2862
|
+
async claimRefund(args) {
|
|
2863
|
+
return claimRefund(
|
|
2864
|
+
this.program,
|
|
2865
|
+
args,
|
|
2866
|
+
this.walletPublicKey
|
|
2867
|
+
);
|
|
2868
|
+
}
|
|
2869
|
+
// ===========================================================================
|
|
2870
|
+
// Sub-Allocation Vesting Instructions
|
|
2871
|
+
// ===========================================================================
|
|
1332
2872
|
/**
|
|
1333
|
-
*
|
|
1334
|
-
* - Regular milestones: Full payout to founder
|
|
1335
|
-
* - Final milestone: LP USDC reserved for PCL, triggers MAE
|
|
2873
|
+
* Initialize sub-allocation vesting after MAE (Market Access Event)
|
|
1336
2874
|
*
|
|
1337
|
-
*
|
|
1338
|
-
*
|
|
2875
|
+
* Creates SubAllocationVesting PDA for a specific sub-allocation ID.
|
|
2876
|
+
* Project must be in Completed state with MAE completed.
|
|
2877
|
+
* Permissionless - anyone can pay to initialize.
|
|
1339
2878
|
*/
|
|
1340
|
-
async
|
|
1341
|
-
return
|
|
2879
|
+
async initializeSubAllocationVesting(args) {
|
|
2880
|
+
return initializeSubAllocationVesting(
|
|
2881
|
+
this.program,
|
|
2882
|
+
args,
|
|
2883
|
+
this.walletPublicKey
|
|
2884
|
+
);
|
|
2885
|
+
}
|
|
2886
|
+
/**
|
|
2887
|
+
* Claim vested tokens from a sub-allocation
|
|
2888
|
+
*
|
|
2889
|
+
* Only the designated recipient wallet can claim tokens.
|
|
2890
|
+
* Project must be Completed and MAE must be completed.
|
|
2891
|
+
*/
|
|
2892
|
+
async claimSubAllocationTokens(args) {
|
|
2893
|
+
return claimSubAllocationTokens(
|
|
2894
|
+
this.program,
|
|
2895
|
+
args,
|
|
2896
|
+
this.walletPublicKey
|
|
2897
|
+
);
|
|
2898
|
+
}
|
|
2899
|
+
// ===========================================================================
|
|
2900
|
+
// Dynamic Tokenomics Instructions
|
|
2901
|
+
// ===========================================================================
|
|
2902
|
+
/**
|
|
2903
|
+
* Add a sub-allocation from the reserve pool (Draft state only)
|
|
2904
|
+
*
|
|
2905
|
+
* Allows founders to add named allocations (advisors, marketing, etc.)
|
|
2906
|
+
* from their reserve pool before submitting for approval.
|
|
2907
|
+
*/
|
|
2908
|
+
async addSubAllocation(args) {
|
|
2909
|
+
return addSubAllocation(
|
|
1342
2910
|
this.program,
|
|
1343
2911
|
args,
|
|
1344
2912
|
this.walletPublicKey
|
|
1345
2913
|
);
|
|
1346
2914
|
}
|
|
1347
2915
|
/**
|
|
1348
|
-
*
|
|
2916
|
+
* Propose an allocation change via governance (post-Draft states)
|
|
1349
2917
|
*
|
|
1350
|
-
*
|
|
1351
|
-
*
|
|
2918
|
+
* Creates a 7-day voting period for investors to approve/reject
|
|
2919
|
+
* a new sub-allocation from the reserve pool.
|
|
1352
2920
|
*/
|
|
1353
|
-
async
|
|
1354
|
-
return
|
|
2921
|
+
async proposeAllocationChange(args) {
|
|
2922
|
+
return proposeAllocationChange(
|
|
1355
2923
|
this.program,
|
|
1356
2924
|
args,
|
|
1357
2925
|
this.walletPublicKey
|
|
1358
2926
|
);
|
|
1359
2927
|
}
|
|
1360
2928
|
/**
|
|
1361
|
-
*
|
|
2929
|
+
* Vote on an allocation change proposal
|
|
1362
2930
|
*
|
|
1363
|
-
*
|
|
1364
|
-
*
|
|
2931
|
+
* Investors can vote for/against using their Investment NFT.
|
|
2932
|
+
* Must meet 7-day hold period for voting eligibility.
|
|
1365
2933
|
*/
|
|
1366
|
-
async
|
|
1367
|
-
return
|
|
2934
|
+
async voteAllocationChange(args) {
|
|
2935
|
+
return voteAllocationChange(
|
|
1368
2936
|
this.program,
|
|
1369
2937
|
args,
|
|
1370
2938
|
this.walletPublicKey
|
|
1371
2939
|
);
|
|
1372
2940
|
}
|
|
1373
2941
|
/**
|
|
1374
|
-
*
|
|
2942
|
+
* Execute an approved allocation change proposal
|
|
1375
2943
|
*
|
|
1376
|
-
*
|
|
1377
|
-
*
|
|
2944
|
+
* Permissionless - anyone can call after voting ends.
|
|
2945
|
+
* Proposal must have passed (>51% approval).
|
|
1378
2946
|
*/
|
|
1379
|
-
async
|
|
1380
|
-
return
|
|
2947
|
+
async executeAllocationChange(args) {
|
|
2948
|
+
return executeAllocationChange(
|
|
1381
2949
|
this.program,
|
|
1382
2950
|
args,
|
|
1383
2951
|
this.walletPublicKey
|
|
1384
2952
|
);
|
|
1385
2953
|
}
|
|
1386
2954
|
// ===========================================================================
|
|
1387
|
-
//
|
|
2955
|
+
// Dynamic Tokenomics Helpers
|
|
1388
2956
|
// ===========================================================================
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
2957
|
+
/**
|
|
2958
|
+
* Get remaining founder pool capacity for sub-allocations in basis points
|
|
2959
|
+
*
|
|
2960
|
+
* Calculates: founder_allocation_bps - sum(sub_allocations.bps)
|
|
2961
|
+
* Sub-allocations (treasury, advisors, marketing) draw from founder's allocation pool.
|
|
2962
|
+
*/
|
|
2963
|
+
async getRemainingFounderPool(projectId) {
|
|
2964
|
+
const tokenomics = await this.fetchTokenomics(projectId);
|
|
2965
|
+
if (!tokenomics) {
|
|
2966
|
+
throw new Error("Tokenomics account not found");
|
|
2967
|
+
}
|
|
2968
|
+
const founderBps = tokenomics.founderAllocationBps || 0;
|
|
2969
|
+
const usedBps = (tokenomics.subAllocations || []).filter((sa) => sa.bps > 0).reduce((sum, sa) => sum + sa.bps, 0);
|
|
2970
|
+
return founderBps - usedBps;
|
|
1395
2971
|
}
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
);
|
|
2972
|
+
/**
|
|
2973
|
+
* Get all active (non-executed, non-expired) allocation proposals
|
|
2974
|
+
*/
|
|
2975
|
+
async getActiveProposals(projectId) {
|
|
2976
|
+
const proposals = await this.fetchAllAllocationProposals(projectId);
|
|
2977
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
2978
|
+
return proposals.filter((p) => {
|
|
2979
|
+
const account = p.account;
|
|
2980
|
+
return !account.executed && account.votingEndsAt.toNumber() > now;
|
|
2981
|
+
});
|
|
2982
|
+
}
|
|
2983
|
+
/**
|
|
2984
|
+
* Get vesting status for a sub-allocation
|
|
2985
|
+
*
|
|
2986
|
+
* Returns claimable amount, total vested, and remaining locked tokens.
|
|
2987
|
+
*/
|
|
2988
|
+
async getSubAllocationVestingStatus(projectId, subAllocationId) {
|
|
2989
|
+
const vesting = await this.fetchSubAllocationVesting(projectId, subAllocationId);
|
|
2990
|
+
if (!vesting) {
|
|
2991
|
+
return null;
|
|
2992
|
+
}
|
|
2993
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
2994
|
+
const cliffEnd = vesting.cliffEnd.toNumber();
|
|
2995
|
+
const vestingEnd = vesting.vestingEnd.toNumber();
|
|
2996
|
+
const totalAmount = vesting.totalAmount.toNumber();
|
|
2997
|
+
const claimedAmount = vesting.claimedAmount.toNumber();
|
|
2998
|
+
if (now < cliffEnd) {
|
|
2999
|
+
return {
|
|
3000
|
+
totalAmount,
|
|
3001
|
+
vestedAmount: 0,
|
|
3002
|
+
claimedAmount,
|
|
3003
|
+
claimableAmount: 0,
|
|
3004
|
+
lockedAmount: totalAmount - claimedAmount,
|
|
3005
|
+
vestingProgress: 0,
|
|
3006
|
+
cliffPassed: false
|
|
3007
|
+
};
|
|
3008
|
+
}
|
|
3009
|
+
if (now >= vestingEnd) {
|
|
3010
|
+
return {
|
|
3011
|
+
totalAmount,
|
|
3012
|
+
vestedAmount: totalAmount,
|
|
3013
|
+
claimedAmount,
|
|
3014
|
+
claimableAmount: totalAmount - claimedAmount,
|
|
3015
|
+
lockedAmount: 0,
|
|
3016
|
+
vestingProgress: 100,
|
|
3017
|
+
cliffPassed: true
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
const vestingDuration = vestingEnd - cliffEnd;
|
|
3021
|
+
const elapsed = now - cliffEnd;
|
|
3022
|
+
const vestedAmount = Math.floor(totalAmount * elapsed / vestingDuration);
|
|
3023
|
+
return {
|
|
3024
|
+
totalAmount,
|
|
3025
|
+
vestedAmount,
|
|
3026
|
+
claimedAmount,
|
|
3027
|
+
claimableAmount: vestedAmount - claimedAmount,
|
|
3028
|
+
lockedAmount: totalAmount - vestedAmount,
|
|
3029
|
+
vestingProgress: Math.floor(elapsed / vestingDuration * 100),
|
|
3030
|
+
cliffPassed: true
|
|
3031
|
+
};
|
|
1402
3032
|
}
|
|
1403
3033
|
// ===========================================================================
|
|
1404
|
-
//
|
|
3034
|
+
// Milestone Price Increase Helpers
|
|
1405
3035
|
// ===========================================================================
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
3036
|
+
/** Base price multiplier constant (10000 BPS = 1.0x) */
|
|
3037
|
+
static PRICE_MULTIPLIER_BASE = 1e4;
|
|
3038
|
+
/**
|
|
3039
|
+
* Get the current price multiplier for a project
|
|
3040
|
+
*
|
|
3041
|
+
* Returns the multiplier in BPS (10000 = 1.0x, 15000 = 1.5x)
|
|
3042
|
+
*
|
|
3043
|
+
* Supports two modes:
|
|
3044
|
+
* - Dynamic mode (priceMultipliers[0] === 0): Uses currentPriceMultiplierBps
|
|
3045
|
+
* calculated dynamically via ZEMYTH formula at each milestone claim
|
|
3046
|
+
* - Static mode (legacy): Uses pre-configured priceMultipliers array lookup
|
|
3047
|
+
*/
|
|
3048
|
+
async getCurrentMultiplier(projectId) {
|
|
3049
|
+
const project = await this.fetchProject(projectId);
|
|
3050
|
+
if (!project) {
|
|
3051
|
+
throw new Error("Project account not found");
|
|
3052
|
+
}
|
|
3053
|
+
const { priceMultipliers, milestonesPassed, milestoneCount, currentPriceMultiplierBps } = project;
|
|
3054
|
+
if (priceMultipliers[0] === 0) {
|
|
3055
|
+
return currentPriceMultiplierBps || _RaiseClient.PRICE_MULTIPLIER_BASE;
|
|
3056
|
+
}
|
|
3057
|
+
const index = milestoneCount === 0 ? 0 : Math.min(milestonesPassed, milestoneCount - 1);
|
|
3058
|
+
return priceMultipliers[index] || _RaiseClient.PRICE_MULTIPLIER_BASE;
|
|
1412
3059
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
)
|
|
3060
|
+
/**
|
|
3061
|
+
* Check if a project uses dynamic price multiplier mode
|
|
3062
|
+
*/
|
|
3063
|
+
async isDynamicMultiplierMode(projectId) {
|
|
3064
|
+
const project = await this.fetchProject(projectId);
|
|
3065
|
+
if (!project) {
|
|
3066
|
+
throw new Error("Project account not found");
|
|
3067
|
+
}
|
|
3068
|
+
return project.priceMultipliers[0] === 0;
|
|
1419
3069
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
3070
|
+
/**
|
|
3071
|
+
* Calculate effective tier prices with current multiplier
|
|
3072
|
+
*
|
|
3073
|
+
* Returns array of tiers with their effective prices after applying
|
|
3074
|
+
* the current milestone multiplier.
|
|
3075
|
+
*/
|
|
3076
|
+
async getEffectiveTierPrices(projectId) {
|
|
3077
|
+
const project = await this.fetchProject(projectId);
|
|
3078
|
+
if (!project) {
|
|
3079
|
+
throw new Error("Project account not found");
|
|
3080
|
+
}
|
|
3081
|
+
const multiplier = await this.getCurrentMultiplier(projectId);
|
|
3082
|
+
const tiers = project.tiers.slice(0, project.tierCount);
|
|
3083
|
+
return tiers.map((tier, index) => ({
|
|
3084
|
+
tierIndex: index,
|
|
3085
|
+
baseAmount: tier.amount,
|
|
3086
|
+
effectiveAmount: tier.amount.mul(new BN(multiplier)).div(new BN(_RaiseClient.PRICE_MULTIPLIER_BASE)),
|
|
3087
|
+
multiplierBps: multiplier
|
|
3088
|
+
}));
|
|
1426
3089
|
}
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
3090
|
+
/**
|
|
3091
|
+
* Get price schedule showing multipliers after each milestone
|
|
3092
|
+
*
|
|
3093
|
+
* Returns array showing what the price multiplier will be
|
|
3094
|
+
* after each milestone passes.
|
|
3095
|
+
*
|
|
3096
|
+
* For dynamic mode projects (priceMultipliers[0] === 0), returns null
|
|
3097
|
+
* as multipliers are calculated dynamically based on deadline timing.
|
|
3098
|
+
*/
|
|
3099
|
+
async getPriceSchedule(projectId) {
|
|
3100
|
+
const project = await this.fetchProject(projectId);
|
|
3101
|
+
if (!project) {
|
|
3102
|
+
throw new Error("Project account not found");
|
|
3103
|
+
}
|
|
3104
|
+
const { priceMultipliers, milestoneCount } = project;
|
|
3105
|
+
if (priceMultipliers[0] === 0) {
|
|
3106
|
+
return null;
|
|
3107
|
+
}
|
|
3108
|
+
return priceMultipliers.slice(0, milestoneCount).map((multiplier, index) => ({
|
|
3109
|
+
afterMilestone: index,
|
|
3110
|
+
multiplierBps: multiplier,
|
|
3111
|
+
multiplierPercent: multiplier / 100
|
|
3112
|
+
// 10000 -> 100%
|
|
3113
|
+
}));
|
|
3114
|
+
}
|
|
3115
|
+
/**
|
|
3116
|
+
* Preview multiplier calculation for dynamic mode projects
|
|
3117
|
+
*
|
|
3118
|
+
* Uses the ZEMYTH formula to calculate what the multiplier would be
|
|
3119
|
+
* given a specific number of remaining milestones and days to deadline.
|
|
3120
|
+
*
|
|
3121
|
+
* Formula: totalMultiplier = 1 + (sqrt(n) / sqrt(15)) × (1 / ln(d/7 + e))
|
|
3122
|
+
*
|
|
3123
|
+
* @param remainingMilestones Number of milestones left (1-10)
|
|
3124
|
+
* @param daysToDeadline Days until next milestone deadline (1-365)
|
|
3125
|
+
* @returns Preview of the multiplier in BPS (10000 = 1.0x, max 20000 = 2.0x)
|
|
3126
|
+
*/
|
|
3127
|
+
previewDynamicMultiplier(remainingMilestones, daysToDeadline) {
|
|
3128
|
+
if (remainingMilestones === 0) {
|
|
3129
|
+
return _RaiseClient.PRICE_MULTIPLIER_BASE;
|
|
3130
|
+
}
|
|
3131
|
+
const days = Math.max(1, Math.min(365, daysToDeadline));
|
|
3132
|
+
const sqrtN = Math.sqrt(remainingMilestones) * 1e3;
|
|
3133
|
+
const milestoneFactor = sqrtN / 3.873;
|
|
3134
|
+
const timeFactor = this.timeFactorLookup(days);
|
|
3135
|
+
const combined = milestoneFactor * timeFactor / 1e3;
|
|
3136
|
+
const bonusBps = Math.min(combined, 1e4);
|
|
3137
|
+
return Math.min(2e4, Math.max(1e4, Math.round(1e4 + bonusBps)));
|
|
3138
|
+
}
|
|
3139
|
+
/** Time factor lookup for dynamic multiplier preview (approximates 1/ln(d/7 + e) × 1000) */
|
|
3140
|
+
timeFactorLookup(days) {
|
|
3141
|
+
if (days <= 7) return 950 - days * 25;
|
|
3142
|
+
if (days <= 14) return 775 - (days - 7) * 20;
|
|
3143
|
+
if (days <= 30) return 635 - (days - 14) * 8;
|
|
3144
|
+
if (days <= 60) return 507 - (days - 30) * 4;
|
|
3145
|
+
if (days <= 90) return 387 - (days - 60) * 3;
|
|
3146
|
+
if (days <= 180) return 297 - (days - 90) * 1;
|
|
3147
|
+
return 250;
|
|
1433
3148
|
}
|
|
1434
3149
|
// ===========================================================================
|
|
1435
|
-
//
|
|
3150
|
+
// Linear Progressive Pricing Helpers (add-linear-progressive-pricing)
|
|
1436
3151
|
// ===========================================================================
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
3152
|
+
/** Constants for progressive pricing */
|
|
3153
|
+
static TIME_ALLOCATION_PERCENT = 50;
|
|
3154
|
+
static MILESTONE_ALLOCATION_PERCENT = 50;
|
|
3155
|
+
/** DEV MODE: Time acceleration multiplier (10 real seconds = 1 simulated day) */
|
|
3156
|
+
static PROGRESSIVE_TIME_MULTIPLIER = 8640;
|
|
3157
|
+
/**
|
|
3158
|
+
* Check if progressive pricing is active for a project
|
|
3159
|
+
*
|
|
3160
|
+
* Progressive pricing is active when milestonePeriodStartedAt > 0,
|
|
3161
|
+
* meaning the first milestone period has been initialized.
|
|
3162
|
+
*/
|
|
3163
|
+
isProgressivePricingActive(project) {
|
|
3164
|
+
return project.milestonePeriodStartedAt.gt(new BN(0));
|
|
3165
|
+
}
|
|
3166
|
+
/**
|
|
3167
|
+
* Calculate time progress for a milestone period
|
|
3168
|
+
*
|
|
3169
|
+
* @param project Project account with progressive pricing fields
|
|
3170
|
+
* @param currentTime Current unix timestamp (seconds)
|
|
3171
|
+
* @returns Progress as ratio 0-1 (capped at 1.0)
|
|
3172
|
+
*/
|
|
3173
|
+
getTimeProgress(project, currentTime) {
|
|
3174
|
+
const startedAt = project.milestonePeriodStartedAt.toNumber();
|
|
3175
|
+
const deadline = project.expectedMilestoneDeadlineTs.toNumber();
|
|
3176
|
+
if (startedAt === 0 || deadline <= startedAt) {
|
|
3177
|
+
return 0;
|
|
3178
|
+
}
|
|
3179
|
+
const rawElapsed = Math.max(0, currentTime - startedAt);
|
|
3180
|
+
const elapsed = rawElapsed * _RaiseClient.PROGRESSIVE_TIME_MULTIPLIER;
|
|
3181
|
+
const expectedDuration = Math.max(1, deadline - startedAt);
|
|
3182
|
+
return Math.min(1, elapsed / expectedDuration);
|
|
3183
|
+
}
|
|
3184
|
+
/**
|
|
3185
|
+
* Calculate the effective multiplier including time-based component
|
|
3186
|
+
*
|
|
3187
|
+
* @param project Project account with progressive pricing fields
|
|
3188
|
+
* @param currentTime Current unix timestamp (seconds)
|
|
3189
|
+
* @returns Effective multiplier in BPS (10000 = 1.0x)
|
|
3190
|
+
*/
|
|
3191
|
+
calculateEffectiveMultiplier(project, currentTime) {
|
|
3192
|
+
if (!this.isProgressivePricingActive(project)) {
|
|
3193
|
+
if (project.priceMultipliers[0] === 0) {
|
|
3194
|
+
return project.currentPriceMultiplierBps || _RaiseClient.PRICE_MULTIPLIER_BASE;
|
|
3195
|
+
}
|
|
3196
|
+
return project.currentPriceMultiplierBps || _RaiseClient.PRICE_MULTIPLIER_BASE;
|
|
3197
|
+
}
|
|
3198
|
+
const timeProgress = this.getTimeProgress(project, currentTime);
|
|
3199
|
+
const timeIncrement = Math.floor(project.timeAllocationBps * timeProgress);
|
|
3200
|
+
return project.milestoneBaseMultiplierBps + timeIncrement;
|
|
3201
|
+
}
|
|
3202
|
+
/**
|
|
3203
|
+
* Preview what the milestone spike will be at a given claim time
|
|
3204
|
+
*
|
|
3205
|
+
* If founder claims early, unused time allocation accumulates to spike.
|
|
3206
|
+
*
|
|
3207
|
+
* @param project Project account with progressive pricing fields
|
|
3208
|
+
* @param claimTime Unix timestamp when claim will happen
|
|
3209
|
+
* @returns Object with spike details
|
|
3210
|
+
*/
|
|
3211
|
+
previewMilestoneSpike(project, claimTime) {
|
|
3212
|
+
const timeProgress = this.getTimeProgress(project, claimTime);
|
|
3213
|
+
const consumedTimeBps = Math.floor(project.timeAllocationBps * timeProgress);
|
|
3214
|
+
const unusedTimeBps = project.timeAllocationBps - consumedTimeBps;
|
|
3215
|
+
const milestoneSpikeBps = project.milestoneAllocationBps + unusedTimeBps;
|
|
3216
|
+
const effectiveMultiplierBps = project.milestoneBaseMultiplierBps + consumedTimeBps;
|
|
3217
|
+
const newBaseBps = effectiveMultiplierBps + milestoneSpikeBps;
|
|
3218
|
+
return {
|
|
3219
|
+
timeProgress,
|
|
3220
|
+
consumedTimeBps,
|
|
3221
|
+
unusedTimeBps,
|
|
3222
|
+
milestoneSpikeBps,
|
|
3223
|
+
effectiveMultiplierBps,
|
|
3224
|
+
newBaseBps
|
|
3225
|
+
};
|
|
3226
|
+
}
|
|
3227
|
+
/**
|
|
3228
|
+
* Get effective tier prices with time-based progressive pricing
|
|
3229
|
+
*
|
|
3230
|
+
* Unlike getEffectiveTierPrices which fetches the project, this takes
|
|
3231
|
+
* the project and current time to calculate prices including time component.
|
|
3232
|
+
*/
|
|
3233
|
+
getProgressiveTierPrices(project, currentTime) {
|
|
3234
|
+
const multiplier = this.calculateEffectiveMultiplier(project, currentTime);
|
|
3235
|
+
const timeProgress = this.getTimeProgress(project, currentTime);
|
|
3236
|
+
const tiers = project.tiers.slice(0, project.tierCount);
|
|
3237
|
+
return tiers.map((tier, index) => ({
|
|
3238
|
+
tierIndex: index,
|
|
3239
|
+
baseAmount: tier.amount,
|
|
3240
|
+
effectiveAmount: tier.amount.mul(new BN(multiplier)).div(new BN(_RaiseClient.PRICE_MULTIPLIER_BASE)),
|
|
3241
|
+
multiplierBps: multiplier,
|
|
3242
|
+
timeProgressPercent: Math.round(timeProgress * 100)
|
|
3243
|
+
}));
|
|
3244
|
+
}
|
|
3245
|
+
// ===========================================================================
|
|
3246
|
+
// Multi-Round Fundraising PDAs
|
|
3247
|
+
// ===========================================================================
|
|
3248
|
+
getFundingRoundPDA(projectPda, roundNumber) {
|
|
3249
|
+
return getFundingRoundPDA(projectPda, roundNumber, this.programId);
|
|
3250
|
+
}
|
|
3251
|
+
getRoundEscrowPDA(projectPda, roundNumber) {
|
|
3252
|
+
return getRoundEscrowPDA(projectPda, roundNumber, this.programId);
|
|
3253
|
+
}
|
|
3254
|
+
getRoundMilestonePDA(projectPda, roundNumber, milestoneIndex) {
|
|
3255
|
+
return getRoundMilestonePDA(projectPda, roundNumber, milestoneIndex, this.programId);
|
|
3256
|
+
}
|
|
3257
|
+
getRoundInvestmentPDA(projectPda, roundNumber, nftMint) {
|
|
3258
|
+
return getRoundInvestmentPDA(projectPda, roundNumber, nftMint, this.programId);
|
|
3259
|
+
}
|
|
3260
|
+
getRoundInvestorMilestoneVestingPDA(projectPda, roundNumber, milestoneIndex, investmentPda) {
|
|
3261
|
+
return getRoundInvestorMilestoneVestingPDA(
|
|
3262
|
+
projectPda,
|
|
3263
|
+
roundNumber,
|
|
3264
|
+
milestoneIndex,
|
|
3265
|
+
investmentPda,
|
|
3266
|
+
this.programId
|
|
1442
3267
|
);
|
|
1443
3268
|
}
|
|
1444
|
-
|
|
1445
|
-
return
|
|
3269
|
+
getFutureRoundVaultPDA(projectPda) {
|
|
3270
|
+
return getFutureRoundVaultPDA(projectPda, this.programId);
|
|
3271
|
+
}
|
|
3272
|
+
getFutureRoundTokenVaultPDA(projectPda) {
|
|
3273
|
+
return getFutureRoundTokenVaultPDA(projectPda, this.programId);
|
|
3274
|
+
}
|
|
3275
|
+
// ===========================================================================
|
|
3276
|
+
// Multi-Round Fundraising Account Fetchers
|
|
3277
|
+
// ===========================================================================
|
|
3278
|
+
async fetchFundingRound(projectId, roundNumber) {
|
|
3279
|
+
return fetchFundingRound(this.program, projectId, roundNumber);
|
|
3280
|
+
}
|
|
3281
|
+
async fetchAllFundingRounds(projectId) {
|
|
3282
|
+
return fetchAllFundingRounds(this.program, projectId);
|
|
3283
|
+
}
|
|
3284
|
+
async fetchRoundMilestone(projectId, roundNumber, milestoneIndex) {
|
|
3285
|
+
return fetchRoundMilestone(this.program, projectId, roundNumber, milestoneIndex);
|
|
3286
|
+
}
|
|
3287
|
+
async fetchRoundInvestment(projectId, roundNumber, nftMint) {
|
|
3288
|
+
return fetchRoundInvestment(this.program, projectId, roundNumber, nftMint);
|
|
3289
|
+
}
|
|
3290
|
+
async fetchFutureRoundVault(projectId) {
|
|
3291
|
+
return fetchFutureRoundVault(this.program, projectId);
|
|
3292
|
+
}
|
|
3293
|
+
// ===========================================================================
|
|
3294
|
+
// Multi-Round Fundraising Instructions
|
|
3295
|
+
// ===========================================================================
|
|
3296
|
+
/**
|
|
3297
|
+
* Open a new funding round (R2, R3, R4...)
|
|
3298
|
+
*
|
|
3299
|
+
* Multi-Round Fundraising: Creates FundingRound PDA, round escrow,
|
|
3300
|
+
* and milestone PDAs for the new round. Tokens come from FutureRoundVault.
|
|
3301
|
+
*
|
|
3302
|
+
* Prerequisites:
|
|
3303
|
+
* - Project must be InProgress or Completed state
|
|
3304
|
+
* - At least 1 milestone must have passed (for InProgress projects)
|
|
3305
|
+
* - No other round currently Open
|
|
3306
|
+
* - Current round must be fully funded before opening next
|
|
3307
|
+
* - Must have future_round_allocation configured in tokenomics
|
|
3308
|
+
*/
|
|
3309
|
+
async openFundingRound(args) {
|
|
3310
|
+
return openFundingRound(
|
|
1446
3311
|
this.program,
|
|
1447
3312
|
args,
|
|
1448
3313
|
this.walletPublicKey
|
|
1449
3314
|
);
|
|
1450
3315
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
3316
|
+
/**
|
|
3317
|
+
* Invest in a funding round (R2, R3, R4...)
|
|
3318
|
+
*
|
|
3319
|
+
* Multi-Round Fundraising: Creates investment NFT and deposits USDC
|
|
3320
|
+
* to the round-specific escrow. Tokens come from FutureRoundVault.
|
|
3321
|
+
*/
|
|
3322
|
+
async investInRound(args) {
|
|
3323
|
+
return investInRound(
|
|
1453
3324
|
this.program,
|
|
1454
3325
|
args,
|
|
1455
3326
|
this.walletPublicKey
|
|
1456
3327
|
);
|
|
1457
3328
|
}
|
|
1458
|
-
|
|
1459
|
-
|
|
3329
|
+
/**
|
|
3330
|
+
* Cancel round investment within 24-hour cooling-off period
|
|
3331
|
+
*
|
|
3332
|
+
* Multi-Round Fundraising: Returns USDC from round escrow,
|
|
3333
|
+
* closes investment account.
|
|
3334
|
+
*/
|
|
3335
|
+
async cancelRoundInvestment(args) {
|
|
3336
|
+
return cancelRoundInvestment(
|
|
1460
3337
|
this.program,
|
|
1461
3338
|
args,
|
|
1462
3339
|
this.walletPublicKey
|
|
1463
3340
|
);
|
|
1464
3341
|
}
|
|
1465
|
-
async releaseHoldback(args) {
|
|
1466
|
-
return releaseHoldback(
|
|
1467
|
-
this.program,
|
|
1468
|
-
args
|
|
1469
|
-
);
|
|
1470
|
-
}
|
|
1471
|
-
// ===========================================================================
|
|
1472
|
-
// ZTM v2.0 Token Distribution Instructions
|
|
1473
|
-
// ===========================================================================
|
|
1474
3342
|
/**
|
|
1475
|
-
*
|
|
3343
|
+
* Submit round milestone for investor review
|
|
1476
3344
|
*
|
|
1477
|
-
*
|
|
1478
|
-
*
|
|
3345
|
+
* Multi-Round Fundraising: Transitions milestone to UnderReview,
|
|
3346
|
+
* sets voting deadline.
|
|
1479
3347
|
*/
|
|
1480
|
-
async
|
|
1481
|
-
return
|
|
3348
|
+
async submitRoundMilestone(args) {
|
|
3349
|
+
return submitRoundMilestone(
|
|
1482
3350
|
this.program,
|
|
1483
3351
|
args,
|
|
1484
3352
|
this.walletPublicKey
|
|
1485
3353
|
);
|
|
1486
3354
|
}
|
|
1487
3355
|
/**
|
|
1488
|
-
*
|
|
1489
|
-
*
|
|
1490
|
-
* ZTM v2.0: Called by cranker after finalize_voting sets distribution_pending = true.
|
|
1491
|
-
* Processes batch of investments, transferring unlocked tokens to NFT holders.
|
|
1492
|
-
* Max batch size: 10 investments per call.
|
|
3356
|
+
* Vote on a round milestone (unified voting - ANY investor can vote)
|
|
1493
3357
|
*
|
|
1494
|
-
*
|
|
3358
|
+
* Multi-Round Fundraising: R1, R2, R3... investors can all vote
|
|
3359
|
+
* on any round's milestones. Investment can be from any round.
|
|
1495
3360
|
*/
|
|
1496
|
-
async
|
|
1497
|
-
return
|
|
3361
|
+
async voteOnRoundMilestone(args) {
|
|
3362
|
+
return voteOnRoundMilestone(
|
|
1498
3363
|
this.program,
|
|
1499
3364
|
args,
|
|
1500
3365
|
this.walletPublicKey
|
|
1501
3366
|
);
|
|
1502
3367
|
}
|
|
1503
3368
|
/**
|
|
1504
|
-
*
|
|
3369
|
+
* Finalize voting on a round milestone
|
|
1505
3370
|
*
|
|
1506
|
-
*
|
|
1507
|
-
*
|
|
3371
|
+
* Multi-Round Fundraising: Processes vote results, transitions
|
|
3372
|
+
* milestone to Passed or Failed state.
|
|
1508
3373
|
*/
|
|
1509
|
-
async
|
|
1510
|
-
return
|
|
3374
|
+
async finalizeRoundVoting(args) {
|
|
3375
|
+
return finalizeRoundVoting(
|
|
1511
3376
|
this.program,
|
|
1512
|
-
args
|
|
1513
|
-
this.walletPublicKey
|
|
3377
|
+
args
|
|
1514
3378
|
);
|
|
1515
3379
|
}
|
|
1516
|
-
// ===========================================================================
|
|
1517
|
-
// ZTM v2.0: Founder Vesting Instructions
|
|
1518
|
-
// ===========================================================================
|
|
1519
3380
|
/**
|
|
1520
|
-
*
|
|
3381
|
+
* Claim milestone funds from a round (founder)
|
|
1521
3382
|
*
|
|
1522
|
-
*
|
|
1523
|
-
*
|
|
1524
|
-
*
|
|
3383
|
+
* Multi-Round Fundraising: Transfers USDC from round escrow
|
|
3384
|
+
* to founder's account.
|
|
3385
|
+
*
|
|
3386
|
+
* @param nextMilestoneDeadline - Deadline for next milestone (required for non-final)
|
|
3387
|
+
* Set to BN(0) for final milestone claims
|
|
1525
3388
|
*/
|
|
1526
|
-
async
|
|
1527
|
-
return
|
|
3389
|
+
async claimRoundMilestoneFunds(args) {
|
|
3390
|
+
return claimRoundMilestoneFunds(
|
|
1528
3391
|
this.program,
|
|
1529
3392
|
args,
|
|
1530
3393
|
this.walletPublicKey
|
|
1531
3394
|
);
|
|
1532
3395
|
}
|
|
1533
3396
|
/**
|
|
1534
|
-
* Claim
|
|
3397
|
+
* Claim instant tokens for a round milestone (investor)
|
|
1535
3398
|
*
|
|
1536
|
-
*
|
|
1537
|
-
*
|
|
3399
|
+
* Multi-Round Fundraising: R2+ investors claim instant portion
|
|
3400
|
+
* when milestone passes. Tokens come from FutureRoundVault.
|
|
1538
3401
|
*/
|
|
1539
|
-
async
|
|
1540
|
-
return
|
|
3402
|
+
async claimRoundInstantTokens(args) {
|
|
3403
|
+
return claimRoundInstantTokens(
|
|
1541
3404
|
this.program,
|
|
1542
3405
|
args,
|
|
1543
3406
|
this.walletPublicKey
|
|
1544
3407
|
);
|
|
1545
3408
|
}
|
|
1546
|
-
// ===========================================================================
|
|
1547
|
-
// ZTM v2.0: Circuit Breaker Instructions
|
|
1548
|
-
// ===========================================================================
|
|
1549
3409
|
/**
|
|
1550
|
-
*
|
|
3410
|
+
* Claim vested tokens for a round milestone (investor)
|
|
1551
3411
|
*
|
|
1552
|
-
*
|
|
1553
|
-
*
|
|
1554
|
-
* Affected investors can use claimMissedUnlock to get their tokens.
|
|
3412
|
+
* Multi-Round Fundraising: R2+ investors claim vested portion
|
|
3413
|
+
* after cliff period. Tokens come from FutureRoundVault.
|
|
1555
3414
|
*/
|
|
1556
|
-
async
|
|
1557
|
-
return
|
|
3415
|
+
async claimRoundVestedTokens(args) {
|
|
3416
|
+
return claimRoundVestedTokens(
|
|
1558
3417
|
this.program,
|
|
1559
3418
|
args,
|
|
1560
|
-
|
|
3419
|
+
this.walletPublicKey
|
|
1561
3420
|
);
|
|
1562
3421
|
}
|
|
1563
3422
|
/**
|
|
1564
|
-
* Claim
|
|
3423
|
+
* Claim early tokens for a round investment (5% after 24h)
|
|
1565
3424
|
*
|
|
1566
|
-
*
|
|
1567
|
-
*
|
|
3425
|
+
* Multi-Round Fundraising: R2+ investors claim 5% of token allocation
|
|
3426
|
+
* 24 hours after investing. Tokens come from FutureRoundVault.
|
|
1568
3427
|
*/
|
|
1569
|
-
async
|
|
1570
|
-
return
|
|
3428
|
+
async claimRoundEarlyTokens(args) {
|
|
3429
|
+
return claimRoundEarlyTokens(
|
|
1571
3430
|
this.program,
|
|
1572
3431
|
args,
|
|
1573
3432
|
this.walletPublicKey
|
|
1574
3433
|
);
|
|
1575
3434
|
}
|
|
1576
3435
|
// ===========================================================================
|
|
1577
|
-
//
|
|
3436
|
+
// Multi-Round Fundraising Helpers
|
|
1578
3437
|
// ===========================================================================
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
3438
|
+
/**
|
|
3439
|
+
* Check if the next funding round can be opened
|
|
3440
|
+
*
|
|
3441
|
+
* Returns eligibility status with reason and next round number.
|
|
3442
|
+
*/
|
|
3443
|
+
async canOpenNextRound(projectId) {
|
|
3444
|
+
return canOpenNextRound(this.program, projectId);
|
|
1585
3445
|
}
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
3446
|
+
/**
|
|
3447
|
+
* Get remaining future round allocation in BPS
|
|
3448
|
+
*/
|
|
3449
|
+
getRemainingFutureRoundAllocation(tokenomics) {
|
|
3450
|
+
return getRemainingFutureRoundAllocation(tokenomics);
|
|
3451
|
+
}
|
|
3452
|
+
/**
|
|
3453
|
+
* Check if a specific round is fully funded
|
|
3454
|
+
*/
|
|
3455
|
+
async isRoundFullyFunded(projectId, roundNumber) {
|
|
3456
|
+
return isRoundFullyFunded(this.program, projectId, roundNumber);
|
|
3457
|
+
}
|
|
3458
|
+
/**
|
|
3459
|
+
* Get round details with computed state
|
|
3460
|
+
*
|
|
3461
|
+
* Returns funding round data with additional computed fields.
|
|
3462
|
+
*/
|
|
3463
|
+
async getRoundDetails(projectId, roundNumber) {
|
|
3464
|
+
const fundingRound = await this.fetchFundingRound(projectId, roundNumber);
|
|
3465
|
+
if (!fundingRound) {
|
|
3466
|
+
return null;
|
|
3467
|
+
}
|
|
3468
|
+
const milestones = [];
|
|
3469
|
+
for (let i = 0; i < fundingRound.milestoneCount; i++) {
|
|
3470
|
+
const milestone = await this.fetchRoundMilestone(projectId, roundNumber, i);
|
|
3471
|
+
if (milestone) {
|
|
3472
|
+
milestones.push(milestone);
|
|
3473
|
+
}
|
|
3474
|
+
}
|
|
3475
|
+
const totalRaised = fundingRound.totalRaised.toNumber();
|
|
3476
|
+
const fundingGoal = fundingRound.fundingGoal.toNumber();
|
|
3477
|
+
const fundingProgress = fundingGoal > 0 ? totalRaised / fundingGoal * 100 : 0;
|
|
3478
|
+
return {
|
|
3479
|
+
...fundingRound,
|
|
3480
|
+
milestones,
|
|
3481
|
+
fundingProgress,
|
|
3482
|
+
isFullyFunded: totalRaised >= fundingGoal
|
|
3483
|
+
};
|
|
1592
3484
|
}
|
|
1593
3485
|
};
|
|
1594
3486
|
|
|
@@ -1627,6 +3519,14 @@ var PivotState = /* @__PURE__ */ ((PivotState2) => {
|
|
|
1627
3519
|
PivotState2["Finalized"] = "finalized";
|
|
1628
3520
|
return PivotState2;
|
|
1629
3521
|
})(PivotState || {});
|
|
3522
|
+
var FundingRoundState = /* @__PURE__ */ ((FundingRoundState2) => {
|
|
3523
|
+
FundingRoundState2["Open"] = "open";
|
|
3524
|
+
FundingRoundState2["Funded"] = "funded";
|
|
3525
|
+
FundingRoundState2["InProgress"] = "inProgress";
|
|
3526
|
+
FundingRoundState2["Completed"] = "completed";
|
|
3527
|
+
FundingRoundState2["Failed"] = "failed";
|
|
3528
|
+
return FundingRoundState2;
|
|
3529
|
+
})(FundingRoundState || {});
|
|
1630
3530
|
var ERROR_CODES = {
|
|
1631
3531
|
// State Transition Errors (6000-6099)
|
|
1632
3532
|
InvalidStateTransition: 6e3,
|
|
@@ -1921,6 +3821,6 @@ function shortenPublicKey(pubkey, chars = 4) {
|
|
|
1921
3821
|
return `${str.slice(0, chars)}...${str.slice(-chars)}`;
|
|
1922
3822
|
}
|
|
1923
3823
|
|
|
1924
|
-
export { ERROR_CODES, ERROR_MESSAGES, EVENT_NAMES, GOVERNANCE, InvestmentTier, MAX_DEADLINE_DURATION_SECONDS, MIN_DEADLINE_DURATION_SECONDS_DEV, MIN_DEADLINE_DURATION_SECONDS_PROD, MilestoneState, NFT, PivotState, ProjectState, RaiseClient, RaiseError, SEEDS, TIER_CONSTRAINTS, TIER_MINIMUMS, TIER_TOKEN_MULTIPLIERS, TIER_VOTE_MULTIPLIERS, TIMING, USDC, VALIDATION, VoteChoice, acceptAdmin, accountExists, approvePivot, approveProject, bigIntToBN, bnToBigInt, bnToNumber, bpsToPercent, calculateDeadline, cancelInvestment, checkAbandonment, claimExitWindowRefund, claimInvestorTokens, claimMilestoneFunds, claimMissedUnlock, claimRefund, claimTokens, claimVestedTokens, completeDistribution, confirmTransaction, createMilestone, depositTokens, distributeTokens, extendMilestoneDeadline, fetchAdminConfig, fetchAllInvestments, fetchAllMilestones, fetchAllVotes, fetchInvestment, fetchMilestone, fetchPivotProposal, fetchProject, fetchProjectByPda, fetchTgeEscrow, fetchVote, filterEventsByName, finalizePivot, finalizeVoting, findEvent, findTierIndex, forceCompleteDistribution, formatDuration, getAdminConfigPDA, getCurrentTimestamp, getErrorMessage, getEscrowPDA, getFounderVaultPDA, getFounderVestingPDA, getInvestmentPDA, getInvestorVaultPDA, getLpTokenVaultPDA, getLpUsdcVaultPDA, getMilestonePDA, getNftMintPDA, getPivotProposalPDA, getProgramAuthorityPDA, getProjectPDA, getProjectPDAs, getScamReportPDA, getTgeEscrowPDA, getTierFromAmount, getTokenMintPDA, getTokenMultiplier, getTokenVaultPDA, getTokenomicsPDA, getTransactionWithRetry, getTreasuryVaultPDA, getVaultAuthorityPDA, getVoteMultiplier, getVotePDA, hasTimestampPassed, initializeAdmin, initializeFounderVesting, initializeProject, invest, isRaiseError, isValidPublicKey, minDeadline, parseError, percentToBps, percentageOf, proposePivot, releaseHoldback, reportScam, resubmitMilestone, setMilestoneDeadline, setTgeDate, shortenPublicKey, submitForApproval, submitMilestone, symbolToBytes, timeRemaining, timestampToDate, transferAdmin, validateDeadline, validateMetadataUri, validateMilestonePercentages, voteOnMilestone, withdrawFromPivot };
|
|
3824
|
+
export { EARLY_TOKEN_COOLING_PERIOD_SECONDS, EARLY_TOKEN_COOLING_PERIOD_SECONDS_DEV, EARLY_TOKEN_RELEASE_BPS, ERROR_CODES, ERROR_MESSAGES, EVENT_NAMES, FundingRoundState, GOVERNANCE, InvestmentTier, MAX_DEADLINE_DURATION_SECONDS, MIN_DEADLINE_DURATION_SECONDS_DEV, MIN_DEADLINE_DURATION_SECONDS_PROD, MilestoneState, NFT, PivotState, ProjectState, RaiseClient, RaiseError, SEEDS, TIER_CONSTRAINTS, TIER_MINIMUMS, TIER_TOKEN_MULTIPLIERS, TIER_VOTE_MULTIPLIERS, TIMING, TOKENOMICS, USDC, VALIDATION, VoteChoice, acceptAdmin, accountExists, approvePivot, approveProject, bigIntToBN, bnToBigInt, bnToNumber, bpsToPercent, calculateDeadline, calculateEarlyTokenAmount, calculateRemainingAllocation, canClaimEarlyTokens, canClaimFounderEarlyTokens, canClaimFounderMilestoneTokens, canClaimRoundEarlyTokens, cancelInvestment, cancelRoundInvestment, checkAbandonment, claimExitWindowRefund, claimInvestorTokens, claimMilestoneFunds, claimMissedUnlock, claimRefund, claimRoundEarlyTokens, claimRoundInstantTokens, claimRoundMilestoneFunds, claimRoundVestedTokens, claimTokens, claimVestedTokens, completeDistribution, confirmTransaction, createMilestone, depositTokens, distributeTokens, extendMilestoneDeadline, fetchAdminConfig, fetchAllFundingRounds, fetchAllInvestments, fetchAllMilestones, fetchAllVotes, fetchFundingRound, fetchFutureRoundVault, fetchInvestment, fetchMilestone, fetchPivotProposal, fetchProject, fetchProjectByPda, fetchRoundInvestment, fetchRoundInvestorMilestoneVesting, fetchRoundMilestone, fetchTgeEscrow, fetchVote, filterEventsByName, finalizePivot, finalizeRoundVoting, finalizeVoting, findEvent, findTierIndex, forceCompleteDistribution, formatDuration, getAdminConfigPDA, getCurrentTimestamp, getErrorMessage, getEscrowPDA, getFounderVaultPDA, getFounderVestingPDA, getFundingRoundPDA, getFutureRoundTokenVaultPDA, getFutureRoundVaultPDA, getInvestmentPDA, getInvestorVaultPDA, getLpTokenVaultPDA, getLpUsdcVaultPDA, getMilestonePDA, getNftMintPDA, getPivotProposalPDA, getProgramAuthorityPDA, getProjectPDA, getProjectPDAs, getRoundEscrowPDA, getRoundInvestmentPDA, getRoundInvestorMilestoneVestingPDA, getRoundMilestonePDA, getRoundNftMintPDA, getScamReportPDA, getTgeEscrowPDA, getTierFromAmount, getTokenMintPDA, getTokenMultiplier, getTokenVaultPDA, getTokenomicsPDA, getTransactionWithRetry, getTreasuryVaultPDA, getVaultAuthorityPDA, getVoteMultiplier, getVotePDA, hasTimestampPassed, initializeAdmin, initializeFounderVesting, initializeProject, invest, investInRound, isRaiseError, isValidPublicKey, minDeadline, openFundingRound, parseError, percentToBps, percentageOf, proposePivot, releaseHoldback, reportScam, requiresBurnForRefund, resubmitMilestone, setMilestoneDeadline, setTgeDate, shortenPublicKey, submitForApproval, submitMilestone, submitRoundMilestone, symbolToBytes, timeRemaining, timestampToDate, transferAdmin, validateDeadline, validateMetadataUri, validateMilestonePercentages, voteOnMilestone, voteOnRoundMilestone, withdrawFromPivot };
|
|
1925
3825
|
//# sourceMappingURL=index.js.map
|
|
1926
3826
|
//# sourceMappingURL=index.js.map
|