@zemyth/raise-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +416 -0
- package/dist/accounts/index.cjs +258 -0
- package/dist/accounts/index.cjs.map +1 -0
- package/dist/accounts/index.d.cts +115 -0
- package/dist/accounts/index.d.ts +115 -0
- package/dist/accounts/index.js +245 -0
- package/dist/accounts/index.js.map +1 -0
- package/dist/constants/index.cjs +174 -0
- package/dist/constants/index.cjs.map +1 -0
- package/dist/constants/index.d.cts +143 -0
- package/dist/constants/index.d.ts +143 -0
- package/dist/constants/index.js +158 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/errors/index.cjs +177 -0
- package/dist/errors/index.cjs.map +1 -0
- package/dist/errors/index.d.cts +83 -0
- package/dist/errors/index.d.ts +83 -0
- package/dist/errors/index.js +170 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.cjs +2063 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +680 -0
- package/dist/index.d.ts +680 -0
- package/dist/index.js +1926 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions/index.cjs +852 -0
- package/dist/instructions/index.cjs.map +1 -0
- package/dist/instructions/index.d.cts +452 -0
- package/dist/instructions/index.d.ts +452 -0
- package/dist/instructions/index.js +809 -0
- package/dist/instructions/index.js.map +1 -0
- package/dist/pdas/index.cjs +241 -0
- package/dist/pdas/index.cjs.map +1 -0
- package/dist/pdas/index.d.cts +171 -0
- package/dist/pdas/index.d.ts +171 -0
- package/dist/pdas/index.js +217 -0
- package/dist/pdas/index.js.map +1 -0
- package/dist/types/index.cjs +44 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.cts +229 -0
- package/dist/types/index.d.ts +229 -0
- package/dist/types/index.js +39 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +130 -0
- package/src/accounts/index.ts +329 -0
- package/src/client.ts +715 -0
- package/src/constants/index.ts +205 -0
- package/src/errors/index.ts +222 -0
- package/src/events/index.ts +256 -0
- package/src/index.ts +253 -0
- package/src/instructions/index.ts +1504 -0
- package/src/pdas/index.ts +404 -0
- package/src/types/index.ts +267 -0
- package/src/utils/index.ts +277 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raise Constants
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the on-chain program constants for client-side validation
|
|
5
|
+
* and display purposes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// PDA Seeds
|
|
10
|
+
// =============================================================================
|
|
11
|
+
|
|
12
|
+
export const SEEDS = {
|
|
13
|
+
PROJECT: 'project',
|
|
14
|
+
MILESTONE: 'milestone',
|
|
15
|
+
INVESTMENT: 'investment',
|
|
16
|
+
VOTE: 'vote',
|
|
17
|
+
ESCROW: 'escrow',
|
|
18
|
+
PIVOT: 'pivot',
|
|
19
|
+
PIVOT_PROPOSAL: 'pivot_proposal',
|
|
20
|
+
TGE_ESCROW: 'tge_escrow',
|
|
21
|
+
TGE_ESCROW_VAULT: 'tge_escrow_vault',
|
|
22
|
+
SCAM_REPORT: 'scam_report',
|
|
23
|
+
ADMIN_CONFIG: 'admin-config',
|
|
24
|
+
NFT_MINT: 'nft_mint',
|
|
25
|
+
AUTHORITY: 'authority',
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// Validation Constants
|
|
30
|
+
// =============================================================================
|
|
31
|
+
|
|
32
|
+
export const VALIDATION = {
|
|
33
|
+
/** Minimum number of milestones per project */
|
|
34
|
+
MIN_MILESTONES: 2,
|
|
35
|
+
/** Maximum number of milestones per project */
|
|
36
|
+
MAX_MILESTONES: 10,
|
|
37
|
+
/** Milestone percentages must sum to this value */
|
|
38
|
+
MILESTONE_PERCENTAGE_SUM: 100,
|
|
39
|
+
/** Maximum funding buffer (110% of goal) */
|
|
40
|
+
MAX_FUNDING_BUFFER_PERCENT: 110,
|
|
41
|
+
/** Maximum metadata URI length */
|
|
42
|
+
MAX_METADATA_URI_LENGTH: 200,
|
|
43
|
+
/** Maximum pivot description length */
|
|
44
|
+
MAX_PIVOT_DESCRIPTION_LEN: 256,
|
|
45
|
+
/** Maximum pivot vision length */
|
|
46
|
+
MAX_PIVOT_VISION_LEN: 512,
|
|
47
|
+
/** Maximum pivot justification length */
|
|
48
|
+
MAX_PIVOT_JUSTIFICATION_LEN: 512,
|
|
49
|
+
} as const;
|
|
50
|
+
|
|
51
|
+
// =============================================================================
|
|
52
|
+
// Timing Constants (in seconds)
|
|
53
|
+
// =============================================================================
|
|
54
|
+
|
|
55
|
+
export const TIMING = {
|
|
56
|
+
/** Production voting period (14 days) */
|
|
57
|
+
VOTING_PERIOD_SECONDS: 1_209_600,
|
|
58
|
+
/** Production hold period (7 days) */
|
|
59
|
+
HOLD_PERIOD_SECONDS: 604_800,
|
|
60
|
+
/** Inactivity timeout (90 days) */
|
|
61
|
+
INACTIVITY_TIMEOUT_SECONDS: 7_776_000,
|
|
62
|
+
/** Abandonment timeout (90 days) */
|
|
63
|
+
ABANDONMENT_TIMEOUT_SECONDS: 7_776_000,
|
|
64
|
+
/** Refund window (14 days) */
|
|
65
|
+
REFUND_WINDOW_SECONDS: 1_209_600,
|
|
66
|
+
/** Pivot withdrawal window (7 days) */
|
|
67
|
+
PIVOT_WITHDRAWAL_WINDOW_SECONDS: 604_800,
|
|
68
|
+
/** Minimum TGE date (15 days from now) */
|
|
69
|
+
TGE_MIN_DAYS: 1_296_000,
|
|
70
|
+
/** Maximum TGE date (90 days from now) */
|
|
71
|
+
TGE_MAX_DAYS: 7_776_000,
|
|
72
|
+
/** Post-TGE holdback period (30 days) */
|
|
73
|
+
POST_TGE_HOLDBACK_DAYS: 2_592_000,
|
|
74
|
+
} as const;
|
|
75
|
+
|
|
76
|
+
// =============================================================================
|
|
77
|
+
// Tier Configuration Constraints
|
|
78
|
+
// =============================================================================
|
|
79
|
+
|
|
80
|
+
export const TIER_CONSTRAINTS = {
|
|
81
|
+
/** Minimum number of tiers */
|
|
82
|
+
MIN_TIERS: 1,
|
|
83
|
+
/** Maximum number of tiers */
|
|
84
|
+
MAX_TIERS: 10,
|
|
85
|
+
/** Minimum tier amount (10 USDC in lamports) */
|
|
86
|
+
MIN_TIER_AMOUNT: 10_000_000n,
|
|
87
|
+
/** Minimum max_lots per tier */
|
|
88
|
+
MIN_TIER_MAX_LOTS: 1,
|
|
89
|
+
/** Minimum token ratio */
|
|
90
|
+
MIN_TIER_TOKEN_RATIO: 1n,
|
|
91
|
+
/** Minimum vote multiplier (100 = 1.0x) */
|
|
92
|
+
MIN_TIER_VOTE_MULTIPLIER: 100,
|
|
93
|
+
} as const;
|
|
94
|
+
|
|
95
|
+
// =============================================================================
|
|
96
|
+
// Investment Tiers (Legacy - kept for backwards compatibility)
|
|
97
|
+
// =============================================================================
|
|
98
|
+
|
|
99
|
+
export enum InvestmentTier {
|
|
100
|
+
Bronze = 'Bronze',
|
|
101
|
+
Silver = 'Silver',
|
|
102
|
+
Gold = 'Gold',
|
|
103
|
+
Platinum = 'Platinum',
|
|
104
|
+
Diamond = 'Diamond',
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Investment tier minimum amounts in USDC lamports (6 decimals) - LEGACY */
|
|
108
|
+
export const TIER_MINIMUMS = {
|
|
109
|
+
[InvestmentTier.Bronze]: 100_000_000n, // 100 USDC
|
|
110
|
+
[InvestmentTier.Silver]: 500_000_000n, // 500 USDC
|
|
111
|
+
[InvestmentTier.Gold]: 1_000_000_000n, // 1,000 USDC
|
|
112
|
+
[InvestmentTier.Platinum]: 5_000_000_000n, // 5,000 USDC
|
|
113
|
+
[InvestmentTier.Diamond]: 10_000_000_000n, // 10,000 USDC
|
|
114
|
+
} as const;
|
|
115
|
+
|
|
116
|
+
/** Vote weight multipliers (scaled by 100) - LEGACY */
|
|
117
|
+
export const TIER_VOTE_MULTIPLIERS = {
|
|
118
|
+
[InvestmentTier.Bronze]: 100, // 1.0x
|
|
119
|
+
[InvestmentTier.Silver]: 120, // 1.2x
|
|
120
|
+
[InvestmentTier.Gold]: 150, // 1.5x
|
|
121
|
+
[InvestmentTier.Platinum]: 200, // 2.0x
|
|
122
|
+
[InvestmentTier.Diamond]: 300, // 3.0x
|
|
123
|
+
} as const;
|
|
124
|
+
|
|
125
|
+
/** Token allocation multipliers (same as vote multipliers) - LEGACY */
|
|
126
|
+
export const TIER_TOKEN_MULTIPLIERS = {
|
|
127
|
+
[InvestmentTier.Bronze]: 100,
|
|
128
|
+
[InvestmentTier.Silver]: 120,
|
|
129
|
+
[InvestmentTier.Gold]: 150,
|
|
130
|
+
[InvestmentTier.Platinum]: 200,
|
|
131
|
+
[InvestmentTier.Diamond]: 300,
|
|
132
|
+
} as const;
|
|
133
|
+
|
|
134
|
+
/** Get tier from investment amount (in lamports) - LEGACY, use project.tiers instead */
|
|
135
|
+
export function getTierFromAmount(amount: bigint): InvestmentTier {
|
|
136
|
+
if (amount >= TIER_MINIMUMS[InvestmentTier.Diamond]) return InvestmentTier.Diamond;
|
|
137
|
+
if (amount >= TIER_MINIMUMS[InvestmentTier.Platinum]) return InvestmentTier.Platinum;
|
|
138
|
+
if (amount >= TIER_MINIMUMS[InvestmentTier.Gold]) return InvestmentTier.Gold;
|
|
139
|
+
if (amount >= TIER_MINIMUMS[InvestmentTier.Silver]) return InvestmentTier.Silver;
|
|
140
|
+
return InvestmentTier.Bronze;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Get vote multiplier for an investment amount - LEGACY */
|
|
144
|
+
export function getVoteMultiplier(amount: bigint): number {
|
|
145
|
+
const tier = getTierFromAmount(amount);
|
|
146
|
+
return TIER_VOTE_MULTIPLIERS[tier] / 100;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Get token multiplier for an investment amount - LEGACY */
|
|
150
|
+
export function getTokenMultiplier(amount: bigint): number {
|
|
151
|
+
const tier = getTierFromAmount(amount);
|
|
152
|
+
return TIER_TOKEN_MULTIPLIERS[tier] / 100;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Find matching tier index for an investment amount (threshold-based)
|
|
157
|
+
* Returns the highest tier where amount >= tier.amount
|
|
158
|
+
*/
|
|
159
|
+
export function findTierIndex(tiers: Array<{ amount: bigint }>, amount: bigint): number | null {
|
|
160
|
+
for (let i = tiers.length - 1; i >= 0; i--) {
|
|
161
|
+
if (amount >= tiers[i].amount) {
|
|
162
|
+
return i;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// =============================================================================
|
|
169
|
+
// Voting and Governance
|
|
170
|
+
// =============================================================================
|
|
171
|
+
|
|
172
|
+
export const GOVERNANCE = {
|
|
173
|
+
/** Scam report threshold (30%) */
|
|
174
|
+
SCAM_THRESHOLD_PERCENT: 30,
|
|
175
|
+
/** Consecutive milestone failures before exit window eligible */
|
|
176
|
+
CONSECUTIVE_FAILURES_THRESHOLD: 3,
|
|
177
|
+
/** Milestone approval threshold (>50% weighted approval per whitepaper voting.md:100-101) */
|
|
178
|
+
MILESTONE_APPROVAL_THRESHOLD_PERCENT: 50,
|
|
179
|
+
} as const;
|
|
180
|
+
|
|
181
|
+
// =============================================================================
|
|
182
|
+
// NFT Constants
|
|
183
|
+
// =============================================================================
|
|
184
|
+
|
|
185
|
+
export const NFT = {
|
|
186
|
+
/** NFT symbol */
|
|
187
|
+
SYMBOL: 'SNI',
|
|
188
|
+
/** NFT name prefix */
|
|
189
|
+
NAME_PREFIX: 'Raise Investment #',
|
|
190
|
+
/** Royalty basis points (2%) */
|
|
191
|
+
ROYALTY_BASIS_POINTS: 200,
|
|
192
|
+
} as const;
|
|
193
|
+
|
|
194
|
+
// =============================================================================
|
|
195
|
+
// USDC Constants
|
|
196
|
+
// =============================================================================
|
|
197
|
+
|
|
198
|
+
export const USDC = {
|
|
199
|
+
/** USDC decimals */
|
|
200
|
+
DECIMALS: 6,
|
|
201
|
+
/** Convert USDC to lamports */
|
|
202
|
+
toAmount: (usdc: number): bigint => BigInt(Math.floor(usdc * 10 ** 6)),
|
|
203
|
+
/** Convert lamports to USDC */
|
|
204
|
+
fromAmount: (lamports: bigint): number => Number(lamports) / 10 ** 6,
|
|
205
|
+
} as const;
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raise Error Handling
|
|
3
|
+
*
|
|
4
|
+
* Maps program error codes to SDK errors with helpful messages.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { AnchorError } from '@coral-xyz/anchor';
|
|
8
|
+
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Error Codes (matching Rust program)
|
|
11
|
+
// =============================================================================
|
|
12
|
+
|
|
13
|
+
export const ERROR_CODES = {
|
|
14
|
+
// State Transition Errors (6000-6099)
|
|
15
|
+
InvalidStateTransition: 6000,
|
|
16
|
+
ProjectNotInOpenState: 6001,
|
|
17
|
+
ProjectNotInProgress: 6002,
|
|
18
|
+
MilestoneNotUnderReview: 6003,
|
|
19
|
+
VotingPeriodEnded: 6004,
|
|
20
|
+
VotingPeriodNotEnded: 6005,
|
|
21
|
+
MilestoneNotPassed: 6006,
|
|
22
|
+
MilestoneAlreadyUnlocked: 6007,
|
|
23
|
+
ProjectAlreadyFunded: 6008,
|
|
24
|
+
ProjectNotFunded: 6009,
|
|
25
|
+
|
|
26
|
+
// Authorization Errors (6100-6199)
|
|
27
|
+
UnauthorizedFounder: 6100,
|
|
28
|
+
UnauthorizedAdmin: 6101,
|
|
29
|
+
NotInvestor: 6102,
|
|
30
|
+
AlreadyVoted: 6103,
|
|
31
|
+
|
|
32
|
+
// Investment Errors (6200-6299)
|
|
33
|
+
InvestmentBelowMinimum: 6200,
|
|
34
|
+
FundingGoalExceeded: 6201,
|
|
35
|
+
InvalidTier: 6202,
|
|
36
|
+
CoolingOffPeriodActive: 6203,
|
|
37
|
+
CoolingOffPeriodExpired: 6204,
|
|
38
|
+
|
|
39
|
+
// Milestone Errors (6300-6399)
|
|
40
|
+
InvalidMilestoneIndex: 6300,
|
|
41
|
+
MilestonePercentageInvalid: 6301,
|
|
42
|
+
TotalPercentageExceeded: 6302,
|
|
43
|
+
MilestoneNotInProgress: 6303,
|
|
44
|
+
MilestoneNotApproved: 6304,
|
|
45
|
+
|
|
46
|
+
// TGE Errors (6400-6499)
|
|
47
|
+
TgeDateNotSet: 6400,
|
|
48
|
+
TgeDateAlreadySet: 6401,
|
|
49
|
+
TgeDateTooSoon: 6402,
|
|
50
|
+
TgeDateTooLate: 6403,
|
|
51
|
+
TgeNotReached: 6404,
|
|
52
|
+
TokensAlreadyClaimed: 6405,
|
|
53
|
+
InsufficientTokensDeposited: 6406,
|
|
54
|
+
|
|
55
|
+
// Pivot Errors (6500-6599)
|
|
56
|
+
PivotAlreadyProposed: 6500,
|
|
57
|
+
NoPivotProposed: 6501,
|
|
58
|
+
PivotNotApproved: 6502,
|
|
59
|
+
PivotWindowNotEnded: 6503,
|
|
60
|
+
PivotWindowEnded: 6504,
|
|
61
|
+
AlreadyWithdrawnFromPivot: 6505,
|
|
62
|
+
|
|
63
|
+
// Refund Errors (6800-6899)
|
|
64
|
+
RefundAlreadyClaimed: 6800,
|
|
65
|
+
RefundNotAvailable: 6801,
|
|
66
|
+
ProjectNotAbandoned: 6802,
|
|
67
|
+
|
|
68
|
+
// Scam Errors (6900-6999)
|
|
69
|
+
ScamReportPeriodEnded: 6900,
|
|
70
|
+
ScamAlreadyReported: 6901,
|
|
71
|
+
ScamNotConfirmed: 6902,
|
|
72
|
+
HoldbackAlreadyReleased: 6903,
|
|
73
|
+
HoldbackPeriodNotEnded: 6904,
|
|
74
|
+
} as const;
|
|
75
|
+
|
|
76
|
+
// =============================================================================
|
|
77
|
+
// Error Messages
|
|
78
|
+
// =============================================================================
|
|
79
|
+
|
|
80
|
+
export const ERROR_MESSAGES: Record<number, string> = {
|
|
81
|
+
// State Transition Errors
|
|
82
|
+
[ERROR_CODES.InvalidStateTransition]: 'Invalid project state transition',
|
|
83
|
+
[ERROR_CODES.ProjectNotInOpenState]: 'Project must be in Open state to accept investments',
|
|
84
|
+
[ERROR_CODES.ProjectNotInProgress]: 'Project must be InProgress to perform this action',
|
|
85
|
+
[ERROR_CODES.MilestoneNotUnderReview]: 'Milestone must be under review to vote',
|
|
86
|
+
[ERROR_CODES.VotingPeriodEnded]: 'Voting period has ended',
|
|
87
|
+
[ERROR_CODES.VotingPeriodNotEnded]: 'Voting period has not ended yet',
|
|
88
|
+
[ERROR_CODES.MilestoneNotPassed]: 'Milestone did not pass voting',
|
|
89
|
+
[ERROR_CODES.MilestoneAlreadyUnlocked]: 'Milestone funds already unlocked',
|
|
90
|
+
[ERROR_CODES.ProjectAlreadyFunded]: 'Project has already reached funding goal',
|
|
91
|
+
[ERROR_CODES.ProjectNotFunded]: 'Project has not reached funding goal',
|
|
92
|
+
|
|
93
|
+
// Authorization Errors
|
|
94
|
+
[ERROR_CODES.UnauthorizedFounder]: 'Only the project founder can perform this action',
|
|
95
|
+
[ERROR_CODES.UnauthorizedAdmin]: 'Only the admin can perform this action',
|
|
96
|
+
[ERROR_CODES.NotInvestor]: 'You must be an investor to perform this action',
|
|
97
|
+
[ERROR_CODES.AlreadyVoted]: 'You have already voted on this',
|
|
98
|
+
|
|
99
|
+
// Investment Errors
|
|
100
|
+
[ERROR_CODES.InvestmentBelowMinimum]: 'Investment amount below minimum tier requirement',
|
|
101
|
+
[ERROR_CODES.FundingGoalExceeded]: 'Investment would exceed funding goal',
|
|
102
|
+
[ERROR_CODES.InvalidTier]: 'Invalid investment tier',
|
|
103
|
+
[ERROR_CODES.CoolingOffPeriodActive]: 'Investment is within 24-hour cooling-off period',
|
|
104
|
+
[ERROR_CODES.CoolingOffPeriodExpired]: 'Cooling-off period has expired, cannot cancel',
|
|
105
|
+
|
|
106
|
+
// Milestone Errors
|
|
107
|
+
[ERROR_CODES.InvalidMilestoneIndex]: 'Invalid milestone index',
|
|
108
|
+
[ERROR_CODES.MilestonePercentageInvalid]: 'Milestone percentage must be between 1-100',
|
|
109
|
+
[ERROR_CODES.TotalPercentageExceeded]: 'Total milestone percentages exceed 100%',
|
|
110
|
+
[ERROR_CODES.MilestoneNotInProgress]: 'Milestone must be in progress',
|
|
111
|
+
[ERROR_CODES.MilestoneNotApproved]: 'Milestone must be approved first',
|
|
112
|
+
|
|
113
|
+
// TGE Errors
|
|
114
|
+
[ERROR_CODES.TgeDateNotSet]: 'TGE date has not been set',
|
|
115
|
+
[ERROR_CODES.TgeDateAlreadySet]: 'TGE date has already been set',
|
|
116
|
+
[ERROR_CODES.TgeDateTooSoon]: 'TGE date must be at least 15 days in the future',
|
|
117
|
+
[ERROR_CODES.TgeDateTooLate]: 'TGE date must be within 90 days',
|
|
118
|
+
[ERROR_CODES.TgeNotReached]: 'TGE date has not been reached',
|
|
119
|
+
[ERROR_CODES.TokensAlreadyClaimed]: 'Tokens have already been claimed',
|
|
120
|
+
[ERROR_CODES.InsufficientTokensDeposited]: 'Insufficient tokens deposited by founder',
|
|
121
|
+
|
|
122
|
+
// Pivot Errors
|
|
123
|
+
[ERROR_CODES.PivotAlreadyProposed]: 'A pivot is already pending',
|
|
124
|
+
[ERROR_CODES.NoPivotProposed]: 'No pivot has been proposed',
|
|
125
|
+
[ERROR_CODES.PivotNotApproved]: 'Pivot has not been approved by admin',
|
|
126
|
+
[ERROR_CODES.PivotWindowNotEnded]: '7-day withdrawal window has not ended',
|
|
127
|
+
[ERROR_CODES.PivotWindowEnded]: '7-day withdrawal window has ended',
|
|
128
|
+
[ERROR_CODES.AlreadyWithdrawnFromPivot]: 'Already withdrawn from this pivot',
|
|
129
|
+
|
|
130
|
+
// Refund Errors
|
|
131
|
+
[ERROR_CODES.RefundAlreadyClaimed]: 'Refund has already been claimed',
|
|
132
|
+
[ERROR_CODES.RefundNotAvailable]: 'Refund is not available',
|
|
133
|
+
[ERROR_CODES.ProjectNotAbandoned]: 'Project has not been abandoned',
|
|
134
|
+
|
|
135
|
+
// Scam Errors
|
|
136
|
+
[ERROR_CODES.ScamReportPeriodEnded]: '30-day scam report period has ended',
|
|
137
|
+
[ERROR_CODES.ScamAlreadyReported]: 'Already reported this project for scam',
|
|
138
|
+
[ERROR_CODES.ScamNotConfirmed]: 'Scam has not been confirmed',
|
|
139
|
+
[ERROR_CODES.HoldbackAlreadyReleased]: 'Holdback has already been released',
|
|
140
|
+
[ERROR_CODES.HoldbackPeriodNotEnded]: '30-day holdback period has not ended',
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// =============================================================================
|
|
144
|
+
// SDK Error Class
|
|
145
|
+
// =============================================================================
|
|
146
|
+
|
|
147
|
+
export class RaiseError extends Error {
|
|
148
|
+
constructor(
|
|
149
|
+
public readonly code: number,
|
|
150
|
+
message: string,
|
|
151
|
+
public readonly logs?: string[]
|
|
152
|
+
) {
|
|
153
|
+
super(message);
|
|
154
|
+
this.name = 'RaiseError';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Create from an Anchor error
|
|
159
|
+
*/
|
|
160
|
+
static fromAnchorError(error: AnchorError): RaiseError {
|
|
161
|
+
const code = error.error.errorCode.number;
|
|
162
|
+
const message = ERROR_MESSAGES[code] || error.error.errorMessage;
|
|
163
|
+
return new RaiseError(code, message, error.logs);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Check if this is a specific error type
|
|
168
|
+
*/
|
|
169
|
+
is(errorCode: number): boolean {
|
|
170
|
+
return this.code === errorCode;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// =============================================================================
|
|
175
|
+
// Error Handling Utilities
|
|
176
|
+
// =============================================================================
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Parse an error and return a RaiseError if it's a program error
|
|
180
|
+
*/
|
|
181
|
+
export function parseError(error: unknown): RaiseError | Error {
|
|
182
|
+
if (error instanceof AnchorError) {
|
|
183
|
+
return RaiseError.fromAnchorError(error);
|
|
184
|
+
}
|
|
185
|
+
if (error instanceof Error) {
|
|
186
|
+
return error;
|
|
187
|
+
}
|
|
188
|
+
return new Error(String(error));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Check if an error is a specific Raise error
|
|
193
|
+
*/
|
|
194
|
+
export function isRaiseError(
|
|
195
|
+
error: unknown,
|
|
196
|
+
code?: number
|
|
197
|
+
): error is RaiseError {
|
|
198
|
+
if (!(error instanceof RaiseError)) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
if (code !== undefined) {
|
|
202
|
+
return error.code === code;
|
|
203
|
+
}
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Get a user-friendly error message
|
|
209
|
+
*/
|
|
210
|
+
export function getErrorMessage(error: unknown): string {
|
|
211
|
+
if (error instanceof RaiseError) {
|
|
212
|
+
return error.message;
|
|
213
|
+
}
|
|
214
|
+
if (error instanceof AnchorError) {
|
|
215
|
+
const code = error.error.errorCode.number;
|
|
216
|
+
return ERROR_MESSAGES[code] || error.error.errorMessage;
|
|
217
|
+
}
|
|
218
|
+
if (error instanceof Error) {
|
|
219
|
+
return error.message;
|
|
220
|
+
}
|
|
221
|
+
return 'An unknown error occurred';
|
|
222
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raise Event Parsing
|
|
3
|
+
*
|
|
4
|
+
* Helpers for parsing program events from transaction logs.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { BN } from '@coral-xyz/anchor';
|
|
8
|
+
import { PublicKey } from '@solana/web3.js';
|
|
9
|
+
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Event Types
|
|
12
|
+
// =============================================================================
|
|
13
|
+
|
|
14
|
+
export interface ProjectCreatedEvent {
|
|
15
|
+
name: 'ProjectCreated';
|
|
16
|
+
data: {
|
|
17
|
+
projectId: BN;
|
|
18
|
+
founder: PublicKey;
|
|
19
|
+
fundingGoal: BN;
|
|
20
|
+
metadataUri: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ProjectApprovedEvent {
|
|
25
|
+
name: 'ProjectApproved';
|
|
26
|
+
data: {
|
|
27
|
+
projectId: BN;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ProjectFundedEvent {
|
|
32
|
+
name: 'ProjectFunded';
|
|
33
|
+
data: {
|
|
34
|
+
projectId: BN;
|
|
35
|
+
amountRaised: BN;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface InvestmentMadeEvent {
|
|
40
|
+
name: 'InvestmentMade';
|
|
41
|
+
data: {
|
|
42
|
+
projectId: BN;
|
|
43
|
+
investor: PublicKey;
|
|
44
|
+
amount: BN;
|
|
45
|
+
nftMint: PublicKey;
|
|
46
|
+
tier: number;
|
|
47
|
+
voteWeight: BN;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface InvestmentCancelledEvent {
|
|
52
|
+
name: 'InvestmentCancelled';
|
|
53
|
+
data: {
|
|
54
|
+
projectId: BN;
|
|
55
|
+
investor: PublicKey;
|
|
56
|
+
amount: BN;
|
|
57
|
+
nftMint: PublicKey;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface MilestoneCreatedEvent {
|
|
62
|
+
name: 'MilestoneCreated';
|
|
63
|
+
data: {
|
|
64
|
+
projectId: BN;
|
|
65
|
+
milestoneIndex: number;
|
|
66
|
+
percentage: number;
|
|
67
|
+
description: string;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface MilestoneSubmittedEvent {
|
|
72
|
+
name: 'MilestoneSubmitted';
|
|
73
|
+
data: {
|
|
74
|
+
projectId: BN;
|
|
75
|
+
milestoneIndex: number;
|
|
76
|
+
votingEndsAt: BN;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface VoteCastEvent {
|
|
81
|
+
name: 'VoteCast';
|
|
82
|
+
data: {
|
|
83
|
+
projectId: BN;
|
|
84
|
+
milestoneIndex: number;
|
|
85
|
+
voter: PublicKey;
|
|
86
|
+
choice: { good: object } | { bad: object };
|
|
87
|
+
weight: BN;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface MilestoneVoteFinalizedEvent {
|
|
92
|
+
name: 'MilestoneVoteFinalized';
|
|
93
|
+
data: {
|
|
94
|
+
projectId: BN;
|
|
95
|
+
milestoneIndex: number;
|
|
96
|
+
passed: boolean;
|
|
97
|
+
yesVotes: BN;
|
|
98
|
+
noVotes: BN;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface FundsUnlockedEvent {
|
|
103
|
+
name: 'FundsUnlocked';
|
|
104
|
+
data: {
|
|
105
|
+
projectId: BN;
|
|
106
|
+
milestoneIndex: number;
|
|
107
|
+
amount: BN;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface TgeDateSetEvent {
|
|
112
|
+
name: 'TgeDateSet';
|
|
113
|
+
data: {
|
|
114
|
+
projectId: BN;
|
|
115
|
+
tgeDate: BN;
|
|
116
|
+
tokenMint: PublicKey;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface TokensDepositedEvent {
|
|
121
|
+
name: 'TokensDeposited';
|
|
122
|
+
data: {
|
|
123
|
+
projectId: BN;
|
|
124
|
+
amount: BN;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface TokensClaimedEvent {
|
|
129
|
+
name: 'TokensClaimed';
|
|
130
|
+
data: {
|
|
131
|
+
projectId: BN;
|
|
132
|
+
investor: PublicKey;
|
|
133
|
+
amount: BN;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface RefundClaimedEvent {
|
|
138
|
+
name: 'RefundClaimed';
|
|
139
|
+
data: {
|
|
140
|
+
projectId: BN;
|
|
141
|
+
investor: PublicKey;
|
|
142
|
+
amount: BN;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface PivotProposedEvent {
|
|
147
|
+
name: 'PivotProposed';
|
|
148
|
+
data: {
|
|
149
|
+
projectId: BN;
|
|
150
|
+
newMetadataUri: string;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface PivotApprovedEvent {
|
|
155
|
+
name: 'PivotApproved';
|
|
156
|
+
data: {
|
|
157
|
+
projectId: BN;
|
|
158
|
+
withdrawalWindowEndsAt: BN;
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface PivotFinalizedEvent {
|
|
163
|
+
name: 'PivotFinalized';
|
|
164
|
+
data: {
|
|
165
|
+
projectId: BN;
|
|
166
|
+
withdrawnAmount: BN;
|
|
167
|
+
withdrawnCount: number;
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface MilestoneReworkedEvent {
|
|
172
|
+
name: 'MilestoneReworked';
|
|
173
|
+
data: {
|
|
174
|
+
projectId: BN;
|
|
175
|
+
milestoneIndex: number;
|
|
176
|
+
milestoneKey: PublicKey;
|
|
177
|
+
consecutiveFailures: number;
|
|
178
|
+
reworkedAt: BN;
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export type RaiseEvent =
|
|
183
|
+
| ProjectCreatedEvent
|
|
184
|
+
| ProjectApprovedEvent
|
|
185
|
+
| ProjectFundedEvent
|
|
186
|
+
| InvestmentMadeEvent
|
|
187
|
+
| InvestmentCancelledEvent
|
|
188
|
+
| MilestoneCreatedEvent
|
|
189
|
+
| MilestoneSubmittedEvent
|
|
190
|
+
| VoteCastEvent
|
|
191
|
+
| MilestoneVoteFinalizedEvent
|
|
192
|
+
| FundsUnlockedEvent
|
|
193
|
+
| TgeDateSetEvent
|
|
194
|
+
| TokensDepositedEvent
|
|
195
|
+
| TokensClaimedEvent
|
|
196
|
+
| RefundClaimedEvent
|
|
197
|
+
| PivotProposedEvent
|
|
198
|
+
| PivotApprovedEvent
|
|
199
|
+
| PivotFinalizedEvent
|
|
200
|
+
| MilestoneReworkedEvent;
|
|
201
|
+
|
|
202
|
+
// =============================================================================
|
|
203
|
+
// Event Parsing
|
|
204
|
+
// =============================================================================
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Event name constants
|
|
208
|
+
*/
|
|
209
|
+
export const EVENT_NAMES = {
|
|
210
|
+
ProjectCreated: 'ProjectCreated',
|
|
211
|
+
ProjectApproved: 'ProjectApproved',
|
|
212
|
+
ProjectFunded: 'ProjectFunded',
|
|
213
|
+
InvestmentMade: 'InvestmentMade',
|
|
214
|
+
InvestmentCancelled: 'InvestmentCancelled',
|
|
215
|
+
MilestoneCreated: 'MilestoneCreated',
|
|
216
|
+
MilestoneSubmitted: 'MilestoneSubmitted',
|
|
217
|
+
VoteCast: 'VoteCast',
|
|
218
|
+
MilestoneVoteFinalized: 'MilestoneVoteFinalized',
|
|
219
|
+
FundsUnlocked: 'FundsUnlocked',
|
|
220
|
+
TgeDateSet: 'TgeDateSet',
|
|
221
|
+
TokensDeposited: 'TokensDeposited',
|
|
222
|
+
TokensClaimed: 'TokensClaimed',
|
|
223
|
+
RefundClaimed: 'RefundClaimed',
|
|
224
|
+
PivotProposed: 'PivotProposed',
|
|
225
|
+
PivotApproved: 'PivotApproved',
|
|
226
|
+
PivotFinalized: 'PivotFinalized',
|
|
227
|
+
MilestoneReworked: 'MilestoneReworked',
|
|
228
|
+
} as const;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Filter events by name
|
|
232
|
+
*
|
|
233
|
+
* @param events - Array of events
|
|
234
|
+
* @param name - Event name to filter
|
|
235
|
+
* @returns Filtered events
|
|
236
|
+
*/
|
|
237
|
+
export function filterEventsByName<T extends RaiseEvent>(
|
|
238
|
+
events: RaiseEvent[],
|
|
239
|
+
name: T['name']
|
|
240
|
+
): T[] {
|
|
241
|
+
return events.filter((e) => e.name === name) as T[];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Get the first event of a specific type
|
|
246
|
+
*
|
|
247
|
+
* @param events - Array of events
|
|
248
|
+
* @param name - Event name to find
|
|
249
|
+
* @returns First matching event or undefined
|
|
250
|
+
*/
|
|
251
|
+
export function findEvent<T extends RaiseEvent>(
|
|
252
|
+
events: RaiseEvent[],
|
|
253
|
+
name: T['name']
|
|
254
|
+
): T | undefined {
|
|
255
|
+
return events.find((e) => e.name === name) as T | undefined;
|
|
256
|
+
}
|