@viwoapp/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/dist/index.js ADDED
@@ -0,0 +1,2346 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ACTION_SCOPES: () => ACTION_SCOPES,
24
+ ActionType: () => ActionType,
25
+ BN: () => import_anchor.BN,
26
+ CONTENT_CONSTANTS: () => CONTENT_CONSTANTS,
27
+ ContentClient: () => ContentClient,
28
+ ContentState: () => ContentState,
29
+ FIVE_A_CONSTANTS: () => FIVE_A_CONSTANTS,
30
+ FeeMethod: () => FeeMethod,
31
+ FiveAClient: () => FiveAClient,
32
+ GASLESS_CONSTANTS: () => GASLESS_CONSTANTS,
33
+ GOVERNANCE_CONSTANTS: () => GOVERNANCE_CONSTANTS,
34
+ GaslessClient: () => GaslessClient,
35
+ GovernanceClient: () => GovernanceClient,
36
+ IdentityClient: () => IdentityClient,
37
+ LOCK_DURATIONS: () => LOCK_DURATIONS,
38
+ PDAs: () => PDAs,
39
+ PROGRAM_IDS: () => PROGRAM_IDS,
40
+ ProposalStatus: () => ProposalStatus,
41
+ RewardsClient: () => RewardsClient,
42
+ SEEDS: () => SEEDS,
43
+ SSCRE_CONSTANTS: () => SSCRE_CONSTANTS,
44
+ STAKING_TIERS: () => STAKING_TIERS,
45
+ StakingClient: () => StakingClient,
46
+ StakingTier: () => StakingTier,
47
+ TransactionBuilder: () => TransactionBuilder,
48
+ VCOIN_DECIMALS: () => VCOIN_DECIMALS,
49
+ VCOIN_INITIAL_CIRCULATING: () => VCOIN_INITIAL_CIRCULATING,
50
+ VCOIN_TOTAL_SUPPLY: () => VCOIN_TOTAL_SUPPLY,
51
+ VEVCOIN_DECIMALS: () => VEVCOIN_DECIMALS,
52
+ VILINK_CONSTANTS: () => VILINK_CONSTANTS,
53
+ VerificationLevel: () => VerificationLevel,
54
+ ViLinkClient: () => ViLinkClient,
55
+ ViWoClient: () => ViWoClient,
56
+ ViWoConnection: () => ViWoConnection,
57
+ dateToTimestamp: () => dateToTimestamp,
58
+ formatVCoin: () => formatVCoin,
59
+ getCurrentTimestamp: () => getCurrentTimestamp,
60
+ parseVCoin: () => parseVCoin,
61
+ timestampToDate: () => timestampToDate
62
+ });
63
+ module.exports = __toCommonJS(index_exports);
64
+
65
+ // src/core/index.ts
66
+ var import_web32 = require("@solana/web3.js");
67
+ var import_anchor = require("@coral-xyz/anchor");
68
+
69
+ // src/constants.ts
70
+ var import_web3 = require("@solana/web3.js");
71
+ var PROGRAM_IDS = {
72
+ vcoinToken: new import_web3.PublicKey("Gg1dtrjAfGYi6NLC31WaJjZNBoucvD98rK2h1u9qrUjn"),
73
+ vevcoinToken: new import_web3.PublicKey("FB39ae9x53FxVL3pER9LqCPEx2TRnEnQP55i838Upnjx"),
74
+ stakingProtocol: new import_web3.PublicKey("6EFcistyr2E81adLUcuBJRr8W2xzpt3D3dFYEcMewpWu"),
75
+ transferHook: new import_web3.PublicKey("9K14FcDRrBeHKD9FPNYeVJaEqJQTac2xspJyb1mM6m48"),
76
+ identityProtocol: new import_web3.PublicKey("3egAds3pFR5oog6iQCN42KPvgih8HQz2FGybNjiVWixG"),
77
+ fiveAProtocol: new import_web3.PublicKey("783PbtJw5cc7yatnr9fsvTGSnkKaV6iJe6E8VUPTYrT8"),
78
+ contentRegistry: new import_web3.PublicKey("MJn1A4MPCBPJGWWuZrtq7bHSo2G289sUwW3ej2wcmLV"),
79
+ governanceProtocol: new import_web3.PublicKey("3R256kBN9iXozjypQFRAmegBhd6HJqXWqdNG7Th78HYe"),
80
+ sscreProtocol: new import_web3.PublicKey("6AJNcQSfoiE2UAeUDyJUBumS9SBwhAdSznoAeYpXrxXZ"),
81
+ vilinkProtocol: new import_web3.PublicKey("CFGXTS2MueQwTYTMMTBQbRWzJtSTC2p4ZRuKPpLDmrv7"),
82
+ gaslessProtocol: new import_web3.PublicKey("FcXJAjzJs8eVY2WTRFXynQBpC7WZUqKZppyp9xS6PaB3")
83
+ };
84
+ var SEEDS = {
85
+ // VCoin
86
+ vcoinConfig: "vcoin-config",
87
+ // veVCoin
88
+ vevcoinConfig: "vevcoin-config",
89
+ userVevcoin: "user-vevcoin",
90
+ // Staking
91
+ stakingPool: "staking-pool",
92
+ userStake: "user-stake",
93
+ // Governance
94
+ governanceConfig: "governance-config",
95
+ proposal: "proposal",
96
+ voteRecord: "vote",
97
+ delegation: "delegation",
98
+ // SSCRE
99
+ poolConfig: "pool-config",
100
+ epoch: "epoch",
101
+ userClaim: "user-claim",
102
+ // ViLink
103
+ vilinkConfig: "vilink-config",
104
+ action: "action",
105
+ userStats: "user-stats",
106
+ dapp: "dapp",
107
+ // Gasless
108
+ gaslessConfig: "gasless-config",
109
+ sessionKey: "session-key",
110
+ userGasless: "user-gasless",
111
+ feeVault: "fee-vault",
112
+ // Identity
113
+ identityConfig: "identity-config",
114
+ identity: "identity",
115
+ // 5A
116
+ fiveAConfig: "five-a-config",
117
+ userScore: "user-score",
118
+ vouch: "vouch",
119
+ // Content
120
+ registryConfig: "registry-config",
121
+ content: "content",
122
+ userEnergy: "user-energy"
123
+ };
124
+ var VCOIN_DECIMALS = 9;
125
+ var VEVCOIN_DECIMALS = 9;
126
+ var VCOIN_TOTAL_SUPPLY = 1e9;
127
+ var VCOIN_INITIAL_CIRCULATING = 1e8;
128
+ var STAKING_TIERS = {
129
+ none: { minStake: 0, feeDiscount: 0, boost: 1, minLock: 0 },
130
+ bronze: { minStake: 1e3, feeDiscount: 10, boost: 1.1, minLock: 0 },
131
+ silver: { minStake: 5e3, feeDiscount: 20, boost: 1.2, minLock: 0 },
132
+ gold: { minStake: 2e4, feeDiscount: 30, boost: 1.3, minLock: 0 },
133
+ platinum: { minStake: 1e5, feeDiscount: 50, boost: 1.4, minLock: 0 }
134
+ };
135
+ var LOCK_DURATIONS = {
136
+ none: 0,
137
+ oneMonth: 30 * 24 * 3600,
138
+ threeMonths: 90 * 24 * 3600,
139
+ sixMonths: 180 * 24 * 3600,
140
+ oneYear: 365 * 24 * 3600
141
+ };
142
+ var SSCRE_CONSTANTS = {
143
+ primaryReserves: 35e7,
144
+ // 350M VCoin
145
+ secondaryReserves: 4e7,
146
+ // 40M VCoin
147
+ epochDuration: 30 * 24 * 3600,
148
+ // 30 days
149
+ claimWindow: 90 * 24 * 3600,
150
+ // 90 days
151
+ gaslessFeeBps: 100,
152
+ // 1%
153
+ minClaimAmount: 1
154
+ // 1 VCoin
155
+ };
156
+ var VILINK_CONSTANTS = {
157
+ maxActionExpiry: 7 * 24 * 3600,
158
+ // 7 days
159
+ minTipAmount: 0.1,
160
+ // 0.1 VCoin
161
+ maxTipAmount: 1e4,
162
+ // 10,000 VCoin
163
+ platformFeeBps: 250
164
+ // 2.5%
165
+ };
166
+ var ACTION_SCOPES = {
167
+ tip: 1 << 0,
168
+ vouch: 1 << 1,
169
+ content: 1 << 2,
170
+ governance: 1 << 3,
171
+ transfer: 1 << 4,
172
+ stake: 1 << 5,
173
+ claim: 1 << 6,
174
+ follow: 1 << 7,
175
+ all: 65535
176
+ };
177
+ var GASLESS_CONSTANTS = {
178
+ sessionDuration: 24 * 3600,
179
+ // 24 hours
180
+ maxSessionActions: 1e3,
181
+ maxSessionSpend: 1e5,
182
+ // 100,000 VCoin
183
+ defaultSolFee: 5e3,
184
+ // 0.000005 SOL
185
+ vcoinFeeMultiplier: 100,
186
+ sscreDeductionBps: 100,
187
+ // 1%
188
+ dailySubsidyBudget: 10,
189
+ // 10 SOL
190
+ maxSubsidizedPerUser: 50
191
+ };
192
+ var FIVE_A_CONSTANTS = {
193
+ maxScore: 1e4,
194
+ // 100.00 with 2 decimal precision
195
+ scoreWeights: {
196
+ authenticity: 25,
197
+ // A1 - "Are you a real person?"
198
+ accuracy: 20,
199
+ // A2 - "Is your content quality?"
200
+ agility: 15,
201
+ // A3 - "Are you fast?"
202
+ activity: 25,
203
+ // A4 - "Do you show up daily?"
204
+ approved: 15
205
+ // A5 - "Does the community like you?"
206
+ },
207
+ scoreMultipliers: {
208
+ "0-20": 0.1,
209
+ "20-40": 0.4,
210
+ "40-60": 0.7,
211
+ "60-80": 1,
212
+ "80-100": 1.2
213
+ }
214
+ };
215
+ var CONTENT_CONSTANTS = {
216
+ maxEnergy: 100,
217
+ energyRegenRate: 10,
218
+ // per hour
219
+ createCost: 10,
220
+ editCost: 5,
221
+ deleteCost: 0
222
+ };
223
+ var GOVERNANCE_CONSTANTS = {
224
+ minProposalThreshold: 100,
225
+ // 100 veVCoin
226
+ votingDuration: 7 * 24 * 3600,
227
+ // 7 days
228
+ executionDelay: 2 * 24 * 3600,
229
+ // 2 days
230
+ vetoWindow: 24 * 3600,
231
+ // 1 day
232
+ quorumBps: 400
233
+ // 4%
234
+ };
235
+
236
+ // src/core/index.ts
237
+ var ViWoConnection = class {
238
+ constructor(config) {
239
+ this.commitment = config.commitment || "confirmed";
240
+ this.connection = new import_web32.Connection(
241
+ config.endpoint,
242
+ {
243
+ commitment: this.commitment,
244
+ wsEndpoint: config.wsEndpoint
245
+ }
246
+ );
247
+ }
248
+ /**
249
+ * Get current slot
250
+ */
251
+ async getSlot() {
252
+ return this.connection.getSlot(this.commitment);
253
+ }
254
+ /**
255
+ * Get current block time
256
+ */
257
+ async getBlockTime() {
258
+ const slot = await this.getSlot();
259
+ return this.connection.getBlockTime(slot);
260
+ }
261
+ /**
262
+ * Check if connection is healthy
263
+ */
264
+ async isHealthy() {
265
+ try {
266
+ await this.connection.getVersion();
267
+ return true;
268
+ } catch {
269
+ return false;
270
+ }
271
+ }
272
+ };
273
+ var PDAs = class {
274
+ constructor(programIds = PROGRAM_IDS) {
275
+ this.programIds = programIds;
276
+ }
277
+ // VCoin PDAs
278
+ getVCoinConfig() {
279
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
280
+ [Buffer.from(SEEDS.vcoinConfig)],
281
+ this.programIds.vcoinToken
282
+ );
283
+ return pda;
284
+ }
285
+ // Staking PDAs
286
+ getStakingPool() {
287
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
288
+ [Buffer.from(SEEDS.stakingPool)],
289
+ this.programIds.stakingProtocol
290
+ );
291
+ return pda;
292
+ }
293
+ getUserStake(user) {
294
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
295
+ [Buffer.from(SEEDS.userStake), user.toBuffer()],
296
+ this.programIds.stakingProtocol
297
+ );
298
+ return pda;
299
+ }
300
+ // Governance PDAs
301
+ getGovernanceConfig() {
302
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
303
+ [Buffer.from(SEEDS.governanceConfig)],
304
+ this.programIds.governanceProtocol
305
+ );
306
+ return pda;
307
+ }
308
+ getProposal(proposalId) {
309
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
310
+ [Buffer.from(SEEDS.proposal), proposalId.toArrayLike(Buffer, "le", 8)],
311
+ this.programIds.governanceProtocol
312
+ );
313
+ return pda;
314
+ }
315
+ getVoteRecord(user, proposal) {
316
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
317
+ [Buffer.from(SEEDS.voteRecord), user.toBuffer(), proposal.toBuffer()],
318
+ this.programIds.governanceProtocol
319
+ );
320
+ return pda;
321
+ }
322
+ // SSCRE PDAs
323
+ getRewardsPoolConfig() {
324
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
325
+ [Buffer.from(SEEDS.poolConfig)],
326
+ this.programIds.sscreProtocol
327
+ );
328
+ return pda;
329
+ }
330
+ getEpochDistribution(epoch) {
331
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
332
+ [Buffer.from(SEEDS.epoch), epoch.toArrayLike(Buffer, "le", 8)],
333
+ this.programIds.sscreProtocol
334
+ );
335
+ return pda;
336
+ }
337
+ getUserClaim(user) {
338
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
339
+ [Buffer.from(SEEDS.userClaim), user.toBuffer()],
340
+ this.programIds.sscreProtocol
341
+ );
342
+ return pda;
343
+ }
344
+ // ViLink PDAs
345
+ getViLinkConfig() {
346
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
347
+ [Buffer.from(SEEDS.vilinkConfig)],
348
+ this.programIds.vilinkProtocol
349
+ );
350
+ return pda;
351
+ }
352
+ getViLinkAction(creator, timestamp) {
353
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
354
+ [
355
+ Buffer.from(SEEDS.action),
356
+ creator.toBuffer(),
357
+ timestamp.toArrayLike(Buffer, "le", 8)
358
+ ],
359
+ this.programIds.vilinkProtocol
360
+ );
361
+ return pda;
362
+ }
363
+ getUserActionStats(user) {
364
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
365
+ [Buffer.from(SEEDS.userStats), user.toBuffer()],
366
+ this.programIds.vilinkProtocol
367
+ );
368
+ return pda;
369
+ }
370
+ // Gasless PDAs
371
+ getGaslessConfig() {
372
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
373
+ [Buffer.from(SEEDS.gaslessConfig)],
374
+ this.programIds.gaslessProtocol
375
+ );
376
+ return pda;
377
+ }
378
+ getSessionKey(user, sessionPubkey) {
379
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
380
+ [
381
+ Buffer.from(SEEDS.sessionKey),
382
+ user.toBuffer(),
383
+ sessionPubkey.toBuffer()
384
+ ],
385
+ this.programIds.gaslessProtocol
386
+ );
387
+ return pda;
388
+ }
389
+ getUserGaslessStats(user) {
390
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
391
+ [Buffer.from(SEEDS.userGasless), user.toBuffer()],
392
+ this.programIds.gaslessProtocol
393
+ );
394
+ return pda;
395
+ }
396
+ // Identity PDAs
397
+ getIdentityConfig() {
398
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
399
+ [Buffer.from(SEEDS.identityConfig)],
400
+ this.programIds.identityProtocol
401
+ );
402
+ return pda;
403
+ }
404
+ getUserIdentity(user) {
405
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
406
+ [Buffer.from(SEEDS.identity), user.toBuffer()],
407
+ this.programIds.identityProtocol
408
+ );
409
+ return pda;
410
+ }
411
+ // 5A Protocol PDAs
412
+ getFiveAConfig() {
413
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
414
+ [Buffer.from(SEEDS.fiveAConfig)],
415
+ this.programIds.fiveAProtocol
416
+ );
417
+ return pda;
418
+ }
419
+ getUserScore(user) {
420
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
421
+ [Buffer.from(SEEDS.userScore), user.toBuffer()],
422
+ this.programIds.fiveAProtocol
423
+ );
424
+ return pda;
425
+ }
426
+ // Content PDAs
427
+ getContentRegistryConfig() {
428
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
429
+ [Buffer.from(SEEDS.registryConfig)],
430
+ this.programIds.contentRegistry
431
+ );
432
+ return pda;
433
+ }
434
+ getContentRecord(contentId) {
435
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
436
+ [Buffer.from(SEEDS.content), Buffer.from(contentId)],
437
+ this.programIds.contentRegistry
438
+ );
439
+ return pda;
440
+ }
441
+ getUserEnergy(user) {
442
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
443
+ [Buffer.from(SEEDS.userEnergy), user.toBuffer()],
444
+ this.programIds.contentRegistry
445
+ );
446
+ return pda;
447
+ }
448
+ };
449
+ var TransactionBuilder = class {
450
+ constructor() {
451
+ this.instructions = [];
452
+ }
453
+ add(instruction) {
454
+ this.instructions.push(instruction);
455
+ return this;
456
+ }
457
+ addMany(instructions) {
458
+ this.instructions.push(...instructions);
459
+ return this;
460
+ }
461
+ build() {
462
+ const tx = new import_web32.Transaction();
463
+ for (const ix of this.instructions) {
464
+ tx.add(ix);
465
+ }
466
+ return tx;
467
+ }
468
+ clear() {
469
+ this.instructions = [];
470
+ return this;
471
+ }
472
+ get length() {
473
+ return this.instructions.length;
474
+ }
475
+ };
476
+ function formatVCoin(amount, decimals = 9) {
477
+ const amountBN = typeof amount === "number" ? new import_anchor.BN(amount) : amount;
478
+ const divisor = new import_anchor.BN(10).pow(new import_anchor.BN(decimals));
479
+ const whole = amountBN.div(divisor).toString();
480
+ const fraction = amountBN.mod(divisor).toString().padStart(decimals, "0");
481
+ return `${whole}.${fraction}`;
482
+ }
483
+ function parseVCoin(amount, decimals = 9) {
484
+ if (typeof amount === "number") {
485
+ amount = amount.toString();
486
+ }
487
+ const [whole, fraction = ""] = amount.split(".");
488
+ const paddedFraction = fraction.padEnd(decimals, "0").slice(0, decimals);
489
+ return new import_anchor.BN(whole + paddedFraction);
490
+ }
491
+ function getCurrentTimestamp() {
492
+ return Math.floor(Date.now() / 1e3);
493
+ }
494
+ function timestampToDate(timestamp) {
495
+ const ts = typeof timestamp === "number" ? timestamp : timestamp.toNumber();
496
+ return new Date(ts * 1e3);
497
+ }
498
+ function dateToTimestamp(date) {
499
+ return Math.floor(date.getTime() / 1e3);
500
+ }
501
+
502
+ // src/types.ts
503
+ var StakingTier = /* @__PURE__ */ ((StakingTier2) => {
504
+ StakingTier2[StakingTier2["None"] = 0] = "None";
505
+ StakingTier2[StakingTier2["Bronze"] = 1] = "Bronze";
506
+ StakingTier2[StakingTier2["Silver"] = 2] = "Silver";
507
+ StakingTier2[StakingTier2["Gold"] = 3] = "Gold";
508
+ StakingTier2[StakingTier2["Platinum"] = 4] = "Platinum";
509
+ return StakingTier2;
510
+ })(StakingTier || {});
511
+ var ProposalStatus = /* @__PURE__ */ ((ProposalStatus2) => {
512
+ ProposalStatus2[ProposalStatus2["Active"] = 0] = "Active";
513
+ ProposalStatus2[ProposalStatus2["Passed"] = 1] = "Passed";
514
+ ProposalStatus2[ProposalStatus2["Rejected"] = 2] = "Rejected";
515
+ ProposalStatus2[ProposalStatus2["Executed"] = 3] = "Executed";
516
+ ProposalStatus2[ProposalStatus2["Cancelled"] = 4] = "Cancelled";
517
+ return ProposalStatus2;
518
+ })(ProposalStatus || {});
519
+ var ActionType = /* @__PURE__ */ ((ActionType2) => {
520
+ ActionType2[ActionType2["Tip"] = 0] = "Tip";
521
+ ActionType2[ActionType2["Vouch"] = 1] = "Vouch";
522
+ ActionType2[ActionType2["Follow"] = 2] = "Follow";
523
+ ActionType2[ActionType2["Challenge"] = 3] = "Challenge";
524
+ ActionType2[ActionType2["Stake"] = 4] = "Stake";
525
+ ActionType2[ActionType2["ContentReact"] = 5] = "ContentReact";
526
+ ActionType2[ActionType2["Delegate"] = 6] = "Delegate";
527
+ ActionType2[ActionType2["Vote"] = 7] = "Vote";
528
+ return ActionType2;
529
+ })(ActionType || {});
530
+ var FeeMethod = /* @__PURE__ */ ((FeeMethod2) => {
531
+ FeeMethod2[FeeMethod2["PlatformSubsidized"] = 0] = "PlatformSubsidized";
532
+ FeeMethod2[FeeMethod2["VCoinDeduction"] = 1] = "VCoinDeduction";
533
+ FeeMethod2[FeeMethod2["SSCREDeduction"] = 2] = "SSCREDeduction";
534
+ return FeeMethod2;
535
+ })(FeeMethod || {});
536
+ var VerificationLevel = /* @__PURE__ */ ((VerificationLevel2) => {
537
+ VerificationLevel2[VerificationLevel2["None"] = 0] = "None";
538
+ VerificationLevel2[VerificationLevel2["Basic"] = 1] = "Basic";
539
+ VerificationLevel2[VerificationLevel2["KYC"] = 2] = "KYC";
540
+ VerificationLevel2[VerificationLevel2["Full"] = 3] = "Full";
541
+ VerificationLevel2[VerificationLevel2["Enhanced"] = 4] = "Enhanced";
542
+ return VerificationLevel2;
543
+ })(VerificationLevel || {});
544
+ var ContentState = /* @__PURE__ */ ((ContentState2) => {
545
+ ContentState2[ContentState2["Active"] = 0] = "Active";
546
+ ContentState2[ContentState2["Hidden"] = 1] = "Hidden";
547
+ ContentState2[ContentState2["Deleted"] = 2] = "Deleted";
548
+ ContentState2[ContentState2["Flagged"] = 3] = "Flagged";
549
+ return ContentState2;
550
+ })(ContentState || {});
551
+
552
+ // src/staking/index.ts
553
+ var import_web33 = require("@solana/web3.js");
554
+ var import_anchor2 = require("@coral-xyz/anchor");
555
+ var StakingClient = class {
556
+ constructor(client) {
557
+ this.client = client;
558
+ }
559
+ /**
560
+ * Get staking pool configuration
561
+ */
562
+ async getPool() {
563
+ try {
564
+ const poolPda = this.client.pdas.getStakingPool();
565
+ const accountInfo = await this.client.connection.connection.getAccountInfo(poolPda);
566
+ if (!accountInfo) {
567
+ return null;
568
+ }
569
+ return {
570
+ authority: new import_web33.PublicKey(accountInfo.data.slice(8, 40)),
571
+ vcoinMint: new import_web33.PublicKey(accountInfo.data.slice(40, 72)),
572
+ vevcoinMint: new import_web33.PublicKey(accountInfo.data.slice(72, 104)),
573
+ totalStaked: new import_anchor2.BN(accountInfo.data.slice(104, 112), "le"),
574
+ totalVevcoinMinted: new import_anchor2.BN(accountInfo.data.slice(112, 120), "le"),
575
+ paused: accountInfo.data[120] !== 0
576
+ };
577
+ } catch {
578
+ return null;
579
+ }
580
+ }
581
+ /**
582
+ * Get user stake information
583
+ */
584
+ async getUserStake(user) {
585
+ const target = user || this.client.publicKey;
586
+ if (!target) {
587
+ throw new Error("No user specified and wallet not connected");
588
+ }
589
+ try {
590
+ const stakePda = this.client.pdas.getUserStake(target);
591
+ const accountInfo = await this.client.connection.connection.getAccountInfo(stakePda);
592
+ if (!accountInfo) {
593
+ return null;
594
+ }
595
+ return {
596
+ user: new import_web33.PublicKey(accountInfo.data.slice(8, 40)),
597
+ stakedAmount: new import_anchor2.BN(accountInfo.data.slice(40, 48), "le"),
598
+ vevcoinBalance: new import_anchor2.BN(accountInfo.data.slice(48, 56), "le"),
599
+ tier: accountInfo.data[56],
600
+ lockEndTime: new import_anchor2.BN(accountInfo.data.slice(57, 65), "le"),
601
+ lastUpdateTime: new import_anchor2.BN(accountInfo.data.slice(65, 73), "le")
602
+ };
603
+ } catch {
604
+ return null;
605
+ }
606
+ }
607
+ /**
608
+ * Calculate tier based on stake amount
609
+ */
610
+ calculateTier(stakeAmount) {
611
+ const amount = typeof stakeAmount === "number" ? stakeAmount : stakeAmount.toNumber() / Math.pow(10, VCOIN_DECIMALS);
612
+ if (amount >= STAKING_TIERS.platinum.minStake) return 4;
613
+ if (amount >= STAKING_TIERS.gold.minStake) return 3;
614
+ if (amount >= STAKING_TIERS.silver.minStake) return 2;
615
+ if (amount >= STAKING_TIERS.bronze.minStake) return 1;
616
+ return 0;
617
+ }
618
+ /**
619
+ * Calculate veVCoin amount for given stake
620
+ * Formula: ve_vcoin = staked_amount × (lock_duration / 4_years) × tier_boost
621
+ */
622
+ calculateVeVCoin(amount, lockDuration) {
623
+ const FOUR_YEARS = 4 * 365 * 24 * 3600;
624
+ const lockRatio = lockDuration / FOUR_YEARS;
625
+ const tier = this.calculateTier(amount);
626
+ const tierBoosts = [1, 1.1, 1.2, 1.3, 1.4];
627
+ const tierBoost = tierBoosts[tier];
628
+ const multiplier = lockRatio * tierBoost;
629
+ const vevcoinAmount = amount.toNumber() * multiplier;
630
+ return new import_anchor2.BN(Math.floor(vevcoinAmount));
631
+ }
632
+ /**
633
+ * Get tier name
634
+ */
635
+ getTierName(tier) {
636
+ const names = ["None", "Bronze", "Silver", "Gold", "Platinum"];
637
+ return names[tier] || "Unknown";
638
+ }
639
+ /**
640
+ * Get tier info
641
+ */
642
+ getTierInfo(tier) {
643
+ const tiers = [
644
+ STAKING_TIERS.none,
645
+ STAKING_TIERS.bronze,
646
+ STAKING_TIERS.silver,
647
+ STAKING_TIERS.gold,
648
+ STAKING_TIERS.platinum
649
+ ];
650
+ return tiers[tier] || STAKING_TIERS.none;
651
+ }
652
+ /**
653
+ * Check if user can unstake
654
+ */
655
+ async canUnstake(user) {
656
+ const stakeInfo = await this.getUserStake(user);
657
+ if (!stakeInfo) {
658
+ return { canUnstake: false, reason: "No active stake found" };
659
+ }
660
+ if (stakeInfo.stakedAmount.isZero()) {
661
+ return { canUnstake: false, reason: "No staked amount" };
662
+ }
663
+ const now = Math.floor(Date.now() / 1e3);
664
+ if (stakeInfo.lockEndTime.toNumber() > now) {
665
+ const remaining = stakeInfo.lockEndTime.toNumber() - now;
666
+ const days = Math.ceil(remaining / 86400);
667
+ return { canUnstake: false, reason: `Lock period active: ${days} days remaining` };
668
+ }
669
+ return { canUnstake: true };
670
+ }
671
+ /**
672
+ * Get staking statistics
673
+ */
674
+ async getStats() {
675
+ const pool = await this.getPool();
676
+ const userStake = this.client.publicKey ? await this.getUserStake() : null;
677
+ return {
678
+ totalStaked: pool ? formatVCoin(pool.totalStaked) : "0",
679
+ totalVevcoin: pool ? formatVCoin(pool.totalVevcoinMinted) : "0",
680
+ userStake: userStake ? formatVCoin(userStake.stakedAmount) : null,
681
+ userVevcoin: userStake ? formatVCoin(userStake.vevcoinBalance) : null,
682
+ userTier: userStake ? this.getTierName(userStake.tier) : null
683
+ };
684
+ }
685
+ // ============ Transaction Building ============
686
+ // Note: Full implementation would use Anchor IDL
687
+ /**
688
+ * Build stake instruction
689
+ * @param params Stake parameters
690
+ * @returns Transaction to sign and send
691
+ */
692
+ async buildStakeTransaction(params) {
693
+ if (!this.client.publicKey) {
694
+ throw new Error("Wallet not connected");
695
+ }
696
+ const tx = new import_web33.Transaction();
697
+ return tx;
698
+ }
699
+ /**
700
+ * Build unstake instruction
701
+ * @returns Transaction to sign and send
702
+ */
703
+ async buildUnstakeTransaction() {
704
+ if (!this.client.publicKey) {
705
+ throw new Error("Wallet not connected");
706
+ }
707
+ const { canUnstake, reason } = await this.canUnstake();
708
+ if (!canUnstake) {
709
+ throw new Error(reason);
710
+ }
711
+ const tx = new import_web33.Transaction();
712
+ return tx;
713
+ }
714
+ /**
715
+ * Build extend lock instruction
716
+ * @param newDuration New lock duration in seconds
717
+ * @returns Transaction to sign and send
718
+ */
719
+ async buildExtendLockTransaction(newDuration) {
720
+ if (!this.client.publicKey) {
721
+ throw new Error("Wallet not connected");
722
+ }
723
+ const tx = new import_web33.Transaction();
724
+ return tx;
725
+ }
726
+ };
727
+
728
+ // src/governance/index.ts
729
+ var import_web34 = require("@solana/web3.js");
730
+ var import_anchor3 = require("@coral-xyz/anchor");
731
+ var GovernanceClient = class {
732
+ constructor(client) {
733
+ this.client = client;
734
+ }
735
+ /**
736
+ * Get governance configuration
737
+ */
738
+ async getConfig() {
739
+ try {
740
+ const configPda = this.client.pdas.getGovernanceConfig();
741
+ const accountInfo = await this.client.connection.connection.getAccountInfo(configPda);
742
+ if (!accountInfo) {
743
+ return null;
744
+ }
745
+ return {
746
+ authority: new import_web34.PublicKey(accountInfo.data.slice(8, 40)),
747
+ proposalCount: new import_anchor3.BN(accountInfo.data.slice(40, 48), "le"),
748
+ vevcoinMint: new import_web34.PublicKey(accountInfo.data.slice(48, 80)),
749
+ paused: accountInfo.data[80] !== 0
750
+ };
751
+ } catch {
752
+ return null;
753
+ }
754
+ }
755
+ /**
756
+ * Get proposal by ID
757
+ */
758
+ async getProposal(proposalId) {
759
+ try {
760
+ const proposalPda = this.client.pdas.getProposal(proposalId);
761
+ const accountInfo = await this.client.connection.connection.getAccountInfo(proposalPda);
762
+ if (!accountInfo) {
763
+ return null;
764
+ }
765
+ const data = accountInfo.data;
766
+ return {
767
+ id: new import_anchor3.BN(data.slice(8, 16), "le"),
768
+ proposer: new import_web34.PublicKey(data.slice(16, 48)),
769
+ title: Buffer.from(data.slice(48, 112)).toString("utf8").replace(/\0/g, ""),
770
+ descriptionHash: new Uint8Array(data.slice(112, 144)),
771
+ startTime: new import_anchor3.BN(data.slice(144, 152), "le"),
772
+ endTime: new import_anchor3.BN(data.slice(152, 160), "le"),
773
+ votesFor: new import_anchor3.BN(data.slice(160, 168), "le"),
774
+ votesAgainst: new import_anchor3.BN(data.slice(168, 176), "le"),
775
+ status: data[176],
776
+ executed: data[177] !== 0,
777
+ category: data[178]
778
+ };
779
+ } catch {
780
+ return null;
781
+ }
782
+ }
783
+ /**
784
+ * Get all active proposals
785
+ */
786
+ async getActiveProposals() {
787
+ const config = await this.getConfig();
788
+ if (!config) return [];
789
+ const proposals = [];
790
+ const now = Math.floor(Date.now() / 1e3);
791
+ const proposalCount = config.proposalCount.toNumber();
792
+ const startFrom = Math.max(0, proposalCount - 20);
793
+ for (let i = startFrom; i < proposalCount; i++) {
794
+ const proposal = await this.getProposal(new import_anchor3.BN(i));
795
+ if (proposal && proposal.endTime.toNumber() > now && proposal.status === 0) {
796
+ proposals.push(proposal);
797
+ }
798
+ }
799
+ return proposals;
800
+ }
801
+ /**
802
+ * Get user's vote record for a proposal
803
+ */
804
+ async getVoteRecord(proposalId, user) {
805
+ const target = user || this.client.publicKey;
806
+ if (!target) {
807
+ throw new Error("No user specified and wallet not connected");
808
+ }
809
+ try {
810
+ const proposalPda = this.client.pdas.getProposal(proposalId);
811
+ const votePda = this.client.pdas.getVoteRecord(target, proposalPda);
812
+ const accountInfo = await this.client.connection.connection.getAccountInfo(votePda);
813
+ if (!accountInfo) {
814
+ return null;
815
+ }
816
+ const data = accountInfo.data;
817
+ return {
818
+ user: new import_web34.PublicKey(data.slice(8, 40)),
819
+ proposal: new import_web34.PublicKey(data.slice(40, 72)),
820
+ votePower: new import_anchor3.BN(data.slice(72, 80), "le"),
821
+ support: data[80] !== 0,
822
+ votedAt: new import_anchor3.BN(data.slice(81, 89), "le")
823
+ };
824
+ } catch {
825
+ return null;
826
+ }
827
+ }
828
+ /**
829
+ * Check if user has voted on a proposal
830
+ */
831
+ async hasVoted(proposalId, user) {
832
+ const voteRecord = await this.getVoteRecord(proposalId, user);
833
+ return voteRecord !== null;
834
+ }
835
+ /**
836
+ * Calculate user's voting power
837
+ */
838
+ async getVotingPower(user) {
839
+ const target = user || this.client.publicKey;
840
+ if (!target) {
841
+ throw new Error("No user specified and wallet not connected");
842
+ }
843
+ const vevcoinBalance = await this.client.getVeVCoinBalance(target);
844
+ const fiveAMultiplier = 1;
845
+ return new import_anchor3.BN(Math.floor(vevcoinBalance.toNumber() * fiveAMultiplier));
846
+ }
847
+ /**
848
+ * Get proposal status text
849
+ */
850
+ getStatusText(status) {
851
+ const statuses = ["Active", "Passed", "Rejected", "Executed", "Cancelled"];
852
+ return statuses[status] || "Unknown";
853
+ }
854
+ /**
855
+ * Check if proposal can be executed
856
+ */
857
+ async canExecute(proposalId) {
858
+ const proposal = await this.getProposal(proposalId);
859
+ if (!proposal) {
860
+ return { canExecute: false, reason: "Proposal not found" };
861
+ }
862
+ if (proposal.executed) {
863
+ return { canExecute: false, reason: "Proposal already executed" };
864
+ }
865
+ if (proposal.status !== 1 /* Passed */) {
866
+ return { canExecute: false, reason: "Proposal has not passed" };
867
+ }
868
+ const now = Math.floor(Date.now() / 1e3);
869
+ const executionDelay = proposal.endTime.toNumber() + GOVERNANCE_CONSTANTS.executionDelay;
870
+ if (now < executionDelay) {
871
+ const remaining = executionDelay - now;
872
+ const hours = Math.ceil(remaining / 3600);
873
+ return { canExecute: false, reason: `Execution delay: ${hours} hours remaining` };
874
+ }
875
+ return { canExecute: true };
876
+ }
877
+ /**
878
+ * Get proposal progress
879
+ */
880
+ async getProposalProgress(proposalId) {
881
+ const proposal = await this.getProposal(proposalId);
882
+ if (!proposal) {
883
+ throw new Error("Proposal not found");
884
+ }
885
+ const totalVotes = proposal.votesFor.add(proposal.votesAgainst);
886
+ const forPct = totalVotes.isZero() ? 0 : proposal.votesFor.toNumber() / totalVotes.toNumber() * 100;
887
+ const againstPct = 100 - forPct;
888
+ const quorumThreshold = new import_anchor3.BN(GOVERNANCE_CONSTANTS.quorumBps).mul(new import_anchor3.BN(1e4));
889
+ const quorumReached = totalVotes.gte(quorumThreshold);
890
+ const now = Math.floor(Date.now() / 1e3);
891
+ const timeRemaining = Math.max(0, proposal.endTime.toNumber() - now);
892
+ return {
893
+ votesFor: formatVCoin(proposal.votesFor),
894
+ votesAgainst: formatVCoin(proposal.votesAgainst),
895
+ totalVotes: formatVCoin(totalVotes),
896
+ forPercentage: forPct,
897
+ againstPercentage: againstPct,
898
+ quorumReached,
899
+ timeRemaining
900
+ };
901
+ }
902
+ // ============ Transaction Building ============
903
+ /**
904
+ * Build create proposal transaction
905
+ */
906
+ async buildCreateProposalTransaction(params) {
907
+ if (!this.client.publicKey) {
908
+ throw new Error("Wallet not connected");
909
+ }
910
+ const votingPower = await this.getVotingPower();
911
+ if (votingPower.toNumber() < GOVERNANCE_CONSTANTS.minProposalThreshold) {
912
+ throw new Error(`Insufficient voting power. Need ${GOVERNANCE_CONSTANTS.minProposalThreshold} veVCoin`);
913
+ }
914
+ const tx = new import_web34.Transaction();
915
+ return tx;
916
+ }
917
+ /**
918
+ * Build vote transaction
919
+ */
920
+ async buildVoteTransaction(proposalId, support) {
921
+ if (!this.client.publicKey) {
922
+ throw new Error("Wallet not connected");
923
+ }
924
+ const hasVoted = await this.hasVoted(proposalId);
925
+ if (hasVoted) {
926
+ throw new Error("Already voted on this proposal");
927
+ }
928
+ const tx = new import_web34.Transaction();
929
+ return tx;
930
+ }
931
+ /**
932
+ * Build execute proposal transaction
933
+ */
934
+ async buildExecuteTransaction(proposalId) {
935
+ if (!this.client.publicKey) {
936
+ throw new Error("Wallet not connected");
937
+ }
938
+ const { canExecute, reason } = await this.canExecute(proposalId);
939
+ if (!canExecute) {
940
+ throw new Error(reason);
941
+ }
942
+ const tx = new import_web34.Transaction();
943
+ return tx;
944
+ }
945
+ };
946
+
947
+ // src/rewards/index.ts
948
+ var import_web35 = require("@solana/web3.js");
949
+ var import_anchor4 = require("@coral-xyz/anchor");
950
+ var RewardsClient = class {
951
+ constructor(client) {
952
+ this.client = client;
953
+ }
954
+ /**
955
+ * Get rewards pool configuration
956
+ */
957
+ async getPoolConfig() {
958
+ try {
959
+ const configPda = this.client.pdas.getRewardsPoolConfig();
960
+ const accountInfo = await this.client.connection.connection.getAccountInfo(configPda);
961
+ if (!accountInfo) {
962
+ return null;
963
+ }
964
+ const data = accountInfo.data;
965
+ return {
966
+ authority: new import_web35.PublicKey(data.slice(8, 40)),
967
+ vcoinMint: new import_web35.PublicKey(data.slice(40, 72)),
968
+ currentEpoch: new import_anchor4.BN(data.slice(72, 80), "le"),
969
+ totalDistributed: new import_anchor4.BN(data.slice(80, 88), "le"),
970
+ remainingReserves: new import_anchor4.BN(data.slice(88, 96), "le"),
971
+ paused: data[96] !== 0
972
+ };
973
+ } catch {
974
+ return null;
975
+ }
976
+ }
977
+ /**
978
+ * Get epoch distribution details
979
+ */
980
+ async getEpochDistribution(epoch) {
981
+ try {
982
+ const epochPda = this.client.pdas.getEpochDistribution(epoch);
983
+ const accountInfo = await this.client.connection.connection.getAccountInfo(epochPda);
984
+ if (!accountInfo) {
985
+ return null;
986
+ }
987
+ const data = accountInfo.data;
988
+ return {
989
+ epoch: new import_anchor4.BN(data.slice(8, 16), "le"),
990
+ merkleRoot: new Uint8Array(data.slice(16, 48)),
991
+ totalAllocation: new import_anchor4.BN(data.slice(48, 56), "le"),
992
+ totalClaimed: new import_anchor4.BN(data.slice(56, 64), "le"),
993
+ claimsCount: new import_anchor4.BN(data.slice(64, 72), "le"),
994
+ isFinalized: data[72] !== 0
995
+ };
996
+ } catch {
997
+ return null;
998
+ }
999
+ }
1000
+ /**
1001
+ * Get current epoch
1002
+ */
1003
+ async getCurrentEpoch() {
1004
+ const config = await this.getPoolConfig();
1005
+ return config?.currentEpoch || new import_anchor4.BN(0);
1006
+ }
1007
+ /**
1008
+ * Get user claim history
1009
+ */
1010
+ async getUserClaim(user) {
1011
+ const target = user || this.client.publicKey;
1012
+ if (!target) {
1013
+ throw new Error("No user specified and wallet not connected");
1014
+ }
1015
+ try {
1016
+ const claimPda = this.client.pdas.getUserClaim(target);
1017
+ const accountInfo = await this.client.connection.connection.getAccountInfo(claimPda);
1018
+ if (!accountInfo) {
1019
+ return null;
1020
+ }
1021
+ const data = accountInfo.data;
1022
+ return {
1023
+ user: new import_web35.PublicKey(data.slice(8, 40)),
1024
+ lastClaimedEpoch: new import_anchor4.BN(data.slice(40, 48), "le"),
1025
+ totalClaimed: new import_anchor4.BN(data.slice(48, 56), "le"),
1026
+ claimsCount: data.readUInt32LE(56)
1027
+ };
1028
+ } catch {
1029
+ return null;
1030
+ }
1031
+ }
1032
+ /**
1033
+ * Check if user has claimed for an epoch
1034
+ */
1035
+ async hasClaimedEpoch(epoch, user) {
1036
+ const userClaim = await this.getUserClaim(user);
1037
+ if (!userClaim) return false;
1038
+ const epochNum = epoch.toNumber();
1039
+ if (epochNum <= 255) {
1040
+ return userClaim.lastClaimedEpoch.gte(epoch);
1041
+ }
1042
+ return userClaim.lastClaimedEpoch.gte(epoch);
1043
+ }
1044
+ /**
1045
+ * Get unclaimed epochs
1046
+ */
1047
+ async getUnclaimedEpochs(user) {
1048
+ const currentEpoch = await this.getCurrentEpoch();
1049
+ const userClaim = await this.getUserClaim(user);
1050
+ const unclaimed = [];
1051
+ const startEpoch = userClaim ? userClaim.lastClaimedEpoch.toNumber() + 1 : 1;
1052
+ for (let e = startEpoch; e <= currentEpoch.toNumber(); e++) {
1053
+ const epochDist = await this.getEpochDistribution(new import_anchor4.BN(e));
1054
+ if (epochDist?.isFinalized) {
1055
+ const now = Math.floor(Date.now() / 1e3);
1056
+ const claimExpiry = epochDist.epoch.toNumber() * SSCRE_CONSTANTS.epochDuration + SSCRE_CONSTANTS.claimWindow;
1057
+ if (now <= claimExpiry) {
1058
+ unclaimed.push(new import_anchor4.BN(e));
1059
+ }
1060
+ }
1061
+ }
1062
+ return unclaimed;
1063
+ }
1064
+ /**
1065
+ * Get rewards statistics
1066
+ */
1067
+ async getStats() {
1068
+ const config = await this.getPoolConfig();
1069
+ const userClaim = this.client.publicKey ? await this.getUserClaim() : null;
1070
+ const totalReserves = SSCRE_CONSTANTS.primaryReserves * 1e9;
1071
+ const remaining = config?.remainingReserves.toNumber() || 0;
1072
+ const reservePct = remaining / totalReserves * 100;
1073
+ return {
1074
+ currentEpoch: config?.currentEpoch.toNumber() || 0,
1075
+ totalDistributed: config ? formatVCoin(config.totalDistributed) : "0",
1076
+ remainingReserves: config ? formatVCoin(config.remainingReserves) : "0",
1077
+ reservePercentage: reservePct,
1078
+ userTotalClaimed: userClaim ? formatVCoin(userClaim.totalClaimed) : null,
1079
+ userClaimsCount: userClaim?.claimsCount || null
1080
+ };
1081
+ }
1082
+ /**
1083
+ * Calculate gasless fee for claim
1084
+ */
1085
+ calculateGaslessFee(amount) {
1086
+ const fee = amount.muln(SSCRE_CONSTANTS.gaslessFeeBps).divn(1e4);
1087
+ return fee;
1088
+ }
1089
+ /**
1090
+ * Calculate net claim amount after fee
1091
+ */
1092
+ calculateNetClaim(amount) {
1093
+ const fee = this.calculateGaslessFee(amount);
1094
+ return amount.sub(fee);
1095
+ }
1096
+ // ============ Merkle Proof Utilities ============
1097
+ /**
1098
+ * Verify merkle proof locally
1099
+ */
1100
+ verifyMerkleProof(proof, root, leaf) {
1101
+ let computedHash = leaf;
1102
+ for (const proofElement of proof) {
1103
+ const combined = new Uint8Array(64);
1104
+ if (this.compareBytes(computedHash, proofElement) < 0) {
1105
+ combined.set(computedHash, 0);
1106
+ combined.set(proofElement, 32);
1107
+ } else {
1108
+ combined.set(proofElement, 0);
1109
+ combined.set(computedHash, 32);
1110
+ }
1111
+ computedHash = this.hashBytes(combined);
1112
+ }
1113
+ return this.compareBytes(computedHash, root) === 0;
1114
+ }
1115
+ /**
1116
+ * Compute leaf hash from user data
1117
+ */
1118
+ computeLeaf(user, amount, epoch) {
1119
+ const data = new Uint8Array(48);
1120
+ data.set(user.toBytes(), 0);
1121
+ data.set(amount.toArrayLike(Buffer, "le", 8), 32);
1122
+ data.set(epoch.toArrayLike(Buffer, "le", 8), 40);
1123
+ return this.hashBytes(data);
1124
+ }
1125
+ compareBytes(a, b) {
1126
+ for (let i = 0; i < Math.min(a.length, b.length); i++) {
1127
+ if (a[i] !== b[i]) {
1128
+ return a[i] - b[i];
1129
+ }
1130
+ }
1131
+ return a.length - b.length;
1132
+ }
1133
+ hashBytes(data) {
1134
+ const hash = new Uint8Array(32);
1135
+ for (let i = 0; i < data.length; i++) {
1136
+ hash[i % 32] ^= data[i];
1137
+ }
1138
+ return hash;
1139
+ }
1140
+ // ============ Transaction Building ============
1141
+ /**
1142
+ * Build claim rewards transaction
1143
+ */
1144
+ async buildClaimTransaction(params) {
1145
+ if (!this.client.publicKey) {
1146
+ throw new Error("Wallet not connected");
1147
+ }
1148
+ if (params.amount.lt(new import_anchor4.BN(SSCRE_CONSTANTS.minClaimAmount * 1e9))) {
1149
+ throw new Error(`Claim amount below minimum: ${SSCRE_CONSTANTS.minClaimAmount} VCoin`);
1150
+ }
1151
+ const hasClaimed = await this.hasClaimedEpoch(params.epoch);
1152
+ if (hasClaimed) {
1153
+ throw new Error("Already claimed for this epoch");
1154
+ }
1155
+ const tx = new import_web35.Transaction();
1156
+ return tx;
1157
+ }
1158
+ };
1159
+
1160
+ // src/vilink/index.ts
1161
+ var import_web36 = require("@solana/web3.js");
1162
+ var import_anchor5 = require("@coral-xyz/anchor");
1163
+ var ViLinkClient = class {
1164
+ constructor(client) {
1165
+ this.client = client;
1166
+ }
1167
+ /**
1168
+ * Get ViLink configuration
1169
+ */
1170
+ async getConfig() {
1171
+ try {
1172
+ const configPda = this.client.pdas.getViLinkConfig();
1173
+ const accountInfo = await this.client.connection.connection.getAccountInfo(configPda);
1174
+ if (!accountInfo) {
1175
+ return null;
1176
+ }
1177
+ const data = accountInfo.data;
1178
+ return {
1179
+ authority: new import_web36.PublicKey(data.slice(8, 40)),
1180
+ vcoinMint: new import_web36.PublicKey(data.slice(40, 72)),
1181
+ treasury: new import_web36.PublicKey(data.slice(72, 104)),
1182
+ enabledActions: data[200],
1183
+ totalActionsCreated: new import_anchor5.BN(data.slice(201, 209), "le"),
1184
+ totalActionsExecuted: new import_anchor5.BN(data.slice(209, 217), "le"),
1185
+ totalTipVolume: new import_anchor5.BN(data.slice(217, 225), "le"),
1186
+ paused: data[225] !== 0,
1187
+ platformFeeBps: data.readUInt16LE(226)
1188
+ };
1189
+ } catch {
1190
+ return null;
1191
+ }
1192
+ }
1193
+ /**
1194
+ * Get action by ID
1195
+ */
1196
+ async getAction(creator, timestamp) {
1197
+ try {
1198
+ const actionPda = this.client.pdas.getViLinkAction(creator, timestamp);
1199
+ const accountInfo = await this.client.connection.connection.getAccountInfo(actionPda);
1200
+ if (!accountInfo) {
1201
+ return null;
1202
+ }
1203
+ const data = accountInfo.data;
1204
+ return {
1205
+ actionId: new Uint8Array(data.slice(8, 40)),
1206
+ creator: new import_web36.PublicKey(data.slice(40, 72)),
1207
+ target: new import_web36.PublicKey(data.slice(72, 104)),
1208
+ actionType: data[104],
1209
+ amount: new import_anchor5.BN(data.slice(105, 113), "le"),
1210
+ expiresAt: new import_anchor5.BN(data.slice(145, 153), "le"),
1211
+ executed: data[153] !== 0,
1212
+ executionCount: data.readUInt32LE(193),
1213
+ maxExecutions: data.readUInt32LE(197)
1214
+ };
1215
+ } catch {
1216
+ return null;
1217
+ }
1218
+ }
1219
+ /**
1220
+ * Get user action statistics
1221
+ */
1222
+ async getUserStats(user) {
1223
+ const target = user || this.client.publicKey;
1224
+ if (!target) {
1225
+ throw new Error("No user specified and wallet not connected");
1226
+ }
1227
+ try {
1228
+ const statsPda = this.client.pdas.getUserActionStats(target);
1229
+ const accountInfo = await this.client.connection.connection.getAccountInfo(statsPda);
1230
+ if (!accountInfo) {
1231
+ return null;
1232
+ }
1233
+ const data = accountInfo.data;
1234
+ return {
1235
+ user: new import_web36.PublicKey(data.slice(8, 40)),
1236
+ actionsCreated: new import_anchor5.BN(data.slice(40, 48), "le"),
1237
+ actionsExecuted: new import_anchor5.BN(data.slice(48, 56), "le"),
1238
+ tipsSent: new import_anchor5.BN(data.slice(56, 64), "le"),
1239
+ tipsReceived: new import_anchor5.BN(data.slice(64, 72), "le"),
1240
+ vcoinSent: new import_anchor5.BN(data.slice(72, 80), "le"),
1241
+ vcoinReceived: new import_anchor5.BN(data.slice(80, 88), "le")
1242
+ };
1243
+ } catch {
1244
+ return null;
1245
+ }
1246
+ }
1247
+ /**
1248
+ * Get action type name
1249
+ */
1250
+ getActionTypeName(actionType) {
1251
+ const names = [
1252
+ "Tip",
1253
+ "Vouch",
1254
+ "Follow",
1255
+ "Challenge",
1256
+ "Stake",
1257
+ "ContentReact",
1258
+ "Delegate",
1259
+ "Vote"
1260
+ ];
1261
+ return names[actionType] || "Unknown";
1262
+ }
1263
+ /**
1264
+ * Check if action type is enabled
1265
+ */
1266
+ async isActionTypeEnabled(actionType) {
1267
+ const config = await this.getConfig();
1268
+ if (!config) return false;
1269
+ return (config.enabledActions & 1 << actionType) !== 0;
1270
+ }
1271
+ /**
1272
+ * Check if action is valid for execution
1273
+ */
1274
+ async isActionValid(creator, timestamp) {
1275
+ const action = await this.getAction(creator, timestamp);
1276
+ if (!action) {
1277
+ return { valid: false, reason: "Action not found" };
1278
+ }
1279
+ const now = getCurrentTimestamp();
1280
+ if (now > action.expiresAt.toNumber()) {
1281
+ return { valid: false, reason: "Action has expired" };
1282
+ }
1283
+ if (action.executed && action.maxExecutions === 1) {
1284
+ return { valid: false, reason: "Action already executed" };
1285
+ }
1286
+ if (action.maxExecutions > 0 && action.executionCount >= action.maxExecutions) {
1287
+ return { valid: false, reason: "Max executions reached" };
1288
+ }
1289
+ return { valid: true };
1290
+ }
1291
+ /**
1292
+ * Calculate platform fee for tip
1293
+ */
1294
+ calculateFee(amount) {
1295
+ const fee = amount.muln(VILINK_CONSTANTS.platformFeeBps).divn(1e4);
1296
+ return {
1297
+ fee,
1298
+ net: amount.sub(fee)
1299
+ };
1300
+ }
1301
+ // ============ URI Utilities ============
1302
+ /**
1303
+ * Generate ViLink URI from action ID
1304
+ */
1305
+ generateUri(actionId, baseUrl = "viwo://action") {
1306
+ const idHex = Buffer.from(actionId).toString("hex");
1307
+ return `${baseUrl}/${idHex}`;
1308
+ }
1309
+ /**
1310
+ * Parse action ID from URI
1311
+ */
1312
+ parseUri(uri) {
1313
+ const match = uri.match(/viwo:\/\/action\/([a-f0-9]{64})/i);
1314
+ if (!match) return null;
1315
+ return new Uint8Array(Buffer.from(match[1], "hex"));
1316
+ }
1317
+ /**
1318
+ * Generate QR code data for action
1319
+ */
1320
+ generateQRData(actionId) {
1321
+ return this.generateUri(actionId, "https://viwoapp.com/action");
1322
+ }
1323
+ /**
1324
+ * Generate shareable link with metadata
1325
+ */
1326
+ generateShareableLink(actionId, metadata) {
1327
+ const baseUri = this.generateUri(actionId, "https://viwoapp.com/action");
1328
+ if (!metadata) return baseUri;
1329
+ const params = new URLSearchParams();
1330
+ if (metadata.title) params.set("t", metadata.title);
1331
+ if (metadata.amount) params.set("a", metadata.amount);
1332
+ return `${baseUri}?${params.toString()}`;
1333
+ }
1334
+ // ============ Transaction Building ============
1335
+ /**
1336
+ * Build create tip action transaction
1337
+ */
1338
+ async buildCreateTipAction(params) {
1339
+ if (!this.client.publicKey) {
1340
+ throw new Error("Wallet not connected");
1341
+ }
1342
+ const minAmount = parseVCoin(VILINK_CONSTANTS.minTipAmount.toString());
1343
+ const maxAmount = parseVCoin(VILINK_CONSTANTS.maxTipAmount.toString());
1344
+ if (params.amount.lt(minAmount)) {
1345
+ throw new Error(`Tip amount below minimum: ${VILINK_CONSTANTS.minTipAmount} VCoin`);
1346
+ }
1347
+ if (params.amount.gt(maxAmount)) {
1348
+ throw new Error(`Tip amount exceeds maximum: ${VILINK_CONSTANTS.maxTipAmount} VCoin`);
1349
+ }
1350
+ const tx = new import_web36.Transaction();
1351
+ return tx;
1352
+ }
1353
+ /**
1354
+ * Build create vouch action transaction
1355
+ */
1356
+ async buildCreateVouchAction(params) {
1357
+ if (!this.client.publicKey) {
1358
+ throw new Error("Wallet not connected");
1359
+ }
1360
+ const tx = new import_web36.Transaction();
1361
+ return tx;
1362
+ }
1363
+ /**
1364
+ * Build create follow action transaction
1365
+ */
1366
+ async buildCreateFollowAction(params) {
1367
+ if (!this.client.publicKey) {
1368
+ throw new Error("Wallet not connected");
1369
+ }
1370
+ const tx = new import_web36.Transaction();
1371
+ return tx;
1372
+ }
1373
+ /**
1374
+ * Build execute tip action transaction
1375
+ */
1376
+ async buildExecuteTipAction(creator, timestamp) {
1377
+ if (!this.client.publicKey) {
1378
+ throw new Error("Wallet not connected");
1379
+ }
1380
+ const { valid, reason } = await this.isActionValid(creator, timestamp);
1381
+ if (!valid) {
1382
+ throw new Error(reason);
1383
+ }
1384
+ const action = await this.getAction(creator, timestamp);
1385
+ if (action?.creator.equals(this.client.publicKey)) {
1386
+ throw new Error("Cannot execute own action");
1387
+ }
1388
+ const tx = new import_web36.Transaction();
1389
+ return tx;
1390
+ }
1391
+ };
1392
+
1393
+ // src/gasless/index.ts
1394
+ var import_web37 = require("@solana/web3.js");
1395
+ var import_anchor6 = require("@coral-xyz/anchor");
1396
+ var GaslessClient = class {
1397
+ constructor(client) {
1398
+ this.client = client;
1399
+ }
1400
+ /**
1401
+ * Get gasless configuration
1402
+ */
1403
+ async getConfig() {
1404
+ try {
1405
+ const configPda = this.client.pdas.getGaslessConfig();
1406
+ const accountInfo = await this.client.connection.connection.getAccountInfo(configPda);
1407
+ if (!accountInfo) {
1408
+ return null;
1409
+ }
1410
+ const data = accountInfo.data;
1411
+ return {
1412
+ authority: new import_web37.PublicKey(data.slice(8, 40)),
1413
+ feePayer: new import_web37.PublicKey(data.slice(40, 72)),
1414
+ vcoinMint: new import_web37.PublicKey(data.slice(72, 104)),
1415
+ dailySubsidyBudget: new import_anchor6.BN(data.slice(136, 144), "le"),
1416
+ solFeePerTx: new import_anchor6.BN(data.slice(144, 152), "le"),
1417
+ vcoinFeeMultiplier: new import_anchor6.BN(data.slice(152, 160), "le"),
1418
+ totalSubsidizedTx: new import_anchor6.BN(data.slice(168, 176), "le"),
1419
+ totalVcoinCollected: new import_anchor6.BN(data.slice(184, 192), "le"),
1420
+ paused: data[192] !== 0
1421
+ };
1422
+ } catch {
1423
+ return null;
1424
+ }
1425
+ }
1426
+ /**
1427
+ * Get session key details
1428
+ */
1429
+ async getSessionKey(user, sessionPubkey) {
1430
+ try {
1431
+ const sessionPda = this.client.pdas.getSessionKey(user, sessionPubkey);
1432
+ const accountInfo = await this.client.connection.connection.getAccountInfo(sessionPda);
1433
+ if (!accountInfo) {
1434
+ return null;
1435
+ }
1436
+ const data = accountInfo.data;
1437
+ return {
1438
+ user: new import_web37.PublicKey(data.slice(8, 40)),
1439
+ sessionPubkey: new import_web37.PublicKey(data.slice(40, 72)),
1440
+ scope: data.readUInt16LE(72),
1441
+ createdAt: new import_anchor6.BN(data.slice(74, 82), "le"),
1442
+ expiresAt: new import_anchor6.BN(data.slice(82, 90), "le"),
1443
+ actionsUsed: data.readUInt32LE(90),
1444
+ maxActions: data.readUInt32LE(94),
1445
+ vcoinSpent: new import_anchor6.BN(data.slice(98, 106), "le"),
1446
+ maxSpend: new import_anchor6.BN(data.slice(106, 114), "le"),
1447
+ isRevoked: data[114] !== 0,
1448
+ feeMethod: data[123]
1449
+ };
1450
+ } catch {
1451
+ return null;
1452
+ }
1453
+ }
1454
+ /**
1455
+ * Get user gasless statistics
1456
+ */
1457
+ async getUserStats(user) {
1458
+ const target = user || this.client.publicKey;
1459
+ if (!target) {
1460
+ throw new Error("No user specified and wallet not connected");
1461
+ }
1462
+ try {
1463
+ const statsPda = this.client.pdas.getUserGaslessStats(target);
1464
+ const accountInfo = await this.client.connection.connection.getAccountInfo(statsPda);
1465
+ if (!accountInfo) {
1466
+ return null;
1467
+ }
1468
+ const data = accountInfo.data;
1469
+ return {
1470
+ user: new import_web37.PublicKey(data.slice(8, 40)),
1471
+ totalGaslessTx: new import_anchor6.BN(data.slice(40, 48), "le"),
1472
+ totalSubsidized: new import_anchor6.BN(data.slice(48, 56), "le"),
1473
+ totalVcoinFees: new import_anchor6.BN(data.slice(56, 64), "le"),
1474
+ sessionsCreated: data.readUInt32LE(72),
1475
+ activeSession: new import_web37.PublicKey(data.slice(76, 108))
1476
+ };
1477
+ } catch {
1478
+ return null;
1479
+ }
1480
+ }
1481
+ /**
1482
+ * Check if session is valid
1483
+ */
1484
+ async isSessionValid(user, sessionPubkey) {
1485
+ const session = await this.getSessionKey(user, sessionPubkey);
1486
+ if (!session) {
1487
+ return { valid: false, reason: "Session not found" };
1488
+ }
1489
+ if (session.isRevoked) {
1490
+ return { valid: false, reason: "Session has been revoked" };
1491
+ }
1492
+ const now = getCurrentTimestamp();
1493
+ if (now > session.expiresAt.toNumber()) {
1494
+ return { valid: false, reason: "Session has expired" };
1495
+ }
1496
+ if (session.actionsUsed >= session.maxActions) {
1497
+ return { valid: false, reason: "Session action limit reached" };
1498
+ }
1499
+ return { valid: true };
1500
+ }
1501
+ /**
1502
+ * Check if action is in session scope
1503
+ */
1504
+ isActionInScope(session, actionScope) {
1505
+ return (session.scope & actionScope) !== 0;
1506
+ }
1507
+ /**
1508
+ * Get remaining session actions
1509
+ */
1510
+ getRemainingActions(session) {
1511
+ return session.maxActions - session.actionsUsed;
1512
+ }
1513
+ /**
1514
+ * Get remaining session spend
1515
+ */
1516
+ getRemainingSpend(session) {
1517
+ return session.maxSpend.sub(session.vcoinSpent);
1518
+ }
1519
+ /**
1520
+ * Get remaining session time
1521
+ */
1522
+ getRemainingTime(session) {
1523
+ const now = getCurrentTimestamp();
1524
+ return Math.max(0, session.expiresAt.toNumber() - now);
1525
+ }
1526
+ /**
1527
+ * Calculate VCoin fee equivalent
1528
+ */
1529
+ async calculateVCoinFee() {
1530
+ const config = await this.getConfig();
1531
+ if (!config) {
1532
+ return new import_anchor6.BN(GASLESS_CONSTANTS.defaultSolFee * GASLESS_CONSTANTS.vcoinFeeMultiplier);
1533
+ }
1534
+ return config.solFeePerTx.mul(config.vcoinFeeMultiplier);
1535
+ }
1536
+ /**
1537
+ * Check if user is eligible for subsidized transactions
1538
+ */
1539
+ async isEligibleForSubsidy(user) {
1540
+ const target = user || this.client.publicKey;
1541
+ if (!target) {
1542
+ throw new Error("No user specified and wallet not connected");
1543
+ }
1544
+ const [config, userStats] = await Promise.all([
1545
+ this.getConfig(),
1546
+ this.getUserStats(target)
1547
+ ]);
1548
+ if (!config) {
1549
+ return { eligible: false, remainingToday: 0, reason: "Config not found" };
1550
+ }
1551
+ const maxPerUser = GASLESS_CONSTANTS.maxSubsidizedPerUser;
1552
+ const usedToday = 0;
1553
+ const remaining = maxPerUser - usedToday;
1554
+ if (remaining <= 0) {
1555
+ return {
1556
+ eligible: false,
1557
+ remainingToday: 0,
1558
+ reason: "Daily limit reached"
1559
+ };
1560
+ }
1561
+ return { eligible: true, remainingToday: remaining };
1562
+ }
1563
+ /**
1564
+ * Get scope names from scope bitmap
1565
+ */
1566
+ getScopeNames(scope) {
1567
+ const names = [];
1568
+ const scopeMap = [
1569
+ { bit: ACTION_SCOPES.tip, name: "Tip" },
1570
+ { bit: ACTION_SCOPES.vouch, name: "Vouch" },
1571
+ { bit: ACTION_SCOPES.content, name: "Content" },
1572
+ { bit: ACTION_SCOPES.governance, name: "Governance" },
1573
+ { bit: ACTION_SCOPES.transfer, name: "Transfer" },
1574
+ { bit: ACTION_SCOPES.stake, name: "Stake" },
1575
+ { bit: ACTION_SCOPES.claim, name: "Claim" },
1576
+ { bit: ACTION_SCOPES.follow, name: "Follow" }
1577
+ ];
1578
+ for (const { bit, name } of scopeMap) {
1579
+ if (scope & bit) {
1580
+ names.push(name);
1581
+ }
1582
+ }
1583
+ return names;
1584
+ }
1585
+ /**
1586
+ * Create scope from action names
1587
+ */
1588
+ createScope(actions) {
1589
+ let scope = 0;
1590
+ const scopeMap = {
1591
+ tip: ACTION_SCOPES.tip,
1592
+ vouch: ACTION_SCOPES.vouch,
1593
+ content: ACTION_SCOPES.content,
1594
+ governance: ACTION_SCOPES.governance,
1595
+ transfer: ACTION_SCOPES.transfer,
1596
+ stake: ACTION_SCOPES.stake,
1597
+ claim: ACTION_SCOPES.claim,
1598
+ follow: ACTION_SCOPES.follow
1599
+ };
1600
+ for (const action of actions) {
1601
+ const bit = scopeMap[action.toLowerCase()];
1602
+ if (bit) {
1603
+ scope |= bit;
1604
+ }
1605
+ }
1606
+ return scope;
1607
+ }
1608
+ // ============ Transaction Building ============
1609
+ /**
1610
+ * Build create session key transaction
1611
+ */
1612
+ async buildCreateSessionTransaction(params) {
1613
+ if (!this.client.publicKey) {
1614
+ throw new Error("Wallet not connected");
1615
+ }
1616
+ if (!params.sessionPubkey) {
1617
+ throw new Error("Session public key required");
1618
+ }
1619
+ if (!params.scope || params.scope === 0) {
1620
+ throw new Error("At least one scope required");
1621
+ }
1622
+ const duration = params.durationSeconds || GASLESS_CONSTANTS.sessionDuration;
1623
+ const maxActions = params.maxActions || GASLESS_CONSTANTS.maxSessionActions;
1624
+ const maxSpend = params.maxSpend || new import_anchor6.BN(GASLESS_CONSTANTS.maxSessionSpend * 1e9);
1625
+ const feeMethod = params.feeMethod ?? 1;
1626
+ const tx = new import_web37.Transaction();
1627
+ return tx;
1628
+ }
1629
+ /**
1630
+ * Build revoke session key transaction
1631
+ */
1632
+ async buildRevokeSessionTransaction(sessionPubkey) {
1633
+ if (!this.client.publicKey) {
1634
+ throw new Error("Wallet not connected");
1635
+ }
1636
+ const session = await this.getSessionKey(this.client.publicKey, sessionPubkey);
1637
+ if (!session) {
1638
+ throw new Error("Session not found");
1639
+ }
1640
+ if (session.isRevoked) {
1641
+ throw new Error("Session already revoked");
1642
+ }
1643
+ const tx = new import_web37.Transaction();
1644
+ return tx;
1645
+ }
1646
+ /**
1647
+ * Build VCoin fee deduction transaction
1648
+ */
1649
+ async buildDeductFeeTransaction(amount) {
1650
+ if (!this.client.publicKey) {
1651
+ throw new Error("Wallet not connected");
1652
+ }
1653
+ const tx = new import_web37.Transaction();
1654
+ return tx;
1655
+ }
1656
+ };
1657
+
1658
+ // src/identity/index.ts
1659
+ var import_web38 = require("@solana/web3.js");
1660
+ var import_anchor7 = require("@coral-xyz/anchor");
1661
+ var IdentityClient = class {
1662
+ constructor(client) {
1663
+ this.client = client;
1664
+ }
1665
+ /**
1666
+ * Get user identity
1667
+ */
1668
+ async getIdentity(user) {
1669
+ const target = user || this.client.publicKey;
1670
+ if (!target) {
1671
+ throw new Error("No user specified and wallet not connected");
1672
+ }
1673
+ try {
1674
+ const identityPda = this.client.pdas.getUserIdentity(target);
1675
+ const accountInfo = await this.client.connection.connection.getAccountInfo(identityPda);
1676
+ if (!accountInfo) {
1677
+ return null;
1678
+ }
1679
+ const data = accountInfo.data;
1680
+ return {
1681
+ user: new import_web38.PublicKey(data.slice(8, 40)),
1682
+ didHash: new Uint8Array(data.slice(40, 72)),
1683
+ verificationLevel: data[72],
1684
+ createdAt: new import_anchor7.BN(data.slice(73, 81), "le"),
1685
+ updatedAt: new import_anchor7.BN(data.slice(81, 89), "le")
1686
+ };
1687
+ } catch {
1688
+ return null;
1689
+ }
1690
+ }
1691
+ /**
1692
+ * Check if user has identity
1693
+ */
1694
+ async hasIdentity(user) {
1695
+ const identity = await this.getIdentity(user);
1696
+ return identity !== null;
1697
+ }
1698
+ /**
1699
+ * Get verification level name
1700
+ */
1701
+ getVerificationLevelName(level) {
1702
+ const levels = ["None", "Basic", "Standard", "Enhanced", "Premium"];
1703
+ return levels[level] || "Unknown";
1704
+ }
1705
+ /**
1706
+ * Get verification level requirements
1707
+ */
1708
+ getVerificationRequirements(level) {
1709
+ const requirements = {
1710
+ 0: [],
1711
+ 1: ["Email verification", "Phone verification"],
1712
+ 2: ["Basic requirements", "Social account linking"],
1713
+ 3: ["Standard requirements", "ID verification"],
1714
+ 4: ["Enhanced requirements", "Face verification", "Address verification"]
1715
+ };
1716
+ return requirements[level] || [];
1717
+ }
1718
+ /**
1719
+ * Get verification level benefits
1720
+ */
1721
+ getVerificationBenefits(level) {
1722
+ const benefits = {
1723
+ 0: ["Basic platform access"],
1724
+ 1: ["Higher withdrawal limits", "Basic rewards eligibility"],
1725
+ 2: ["Full rewards eligibility", "Vouch capabilities"],
1726
+ 3: ["Priority support", "Enhanced trust score"],
1727
+ 4: ["VIP status", "Governance proposal creation", "Maximum limits"]
1728
+ };
1729
+ return benefits[level] || [];
1730
+ }
1731
+ // ============ Transaction Building ============
1732
+ /**
1733
+ * Build create identity transaction
1734
+ */
1735
+ async buildCreateIdentityTransaction(didHash) {
1736
+ if (!this.client.publicKey) {
1737
+ throw new Error("Wallet not connected");
1738
+ }
1739
+ const existing = await this.getIdentity();
1740
+ if (existing) {
1741
+ throw new Error("Identity already exists");
1742
+ }
1743
+ if (didHash.length !== 32) {
1744
+ throw new Error("DID hash must be 32 bytes");
1745
+ }
1746
+ const tx = new import_web38.Transaction();
1747
+ return tx;
1748
+ }
1749
+ /**
1750
+ * Build update DID hash transaction
1751
+ */
1752
+ async buildUpdateDidHashTransaction(newDidHash) {
1753
+ if (!this.client.publicKey) {
1754
+ throw new Error("Wallet not connected");
1755
+ }
1756
+ if (newDidHash.length !== 32) {
1757
+ throw new Error("DID hash must be 32 bytes");
1758
+ }
1759
+ const tx = new import_web38.Transaction();
1760
+ return tx;
1761
+ }
1762
+ };
1763
+
1764
+ // src/fivea/index.ts
1765
+ var import_web39 = require("@solana/web3.js");
1766
+ var import_anchor8 = require("@coral-xyz/anchor");
1767
+ var FiveAClient = class {
1768
+ constructor(client) {
1769
+ this.client = client;
1770
+ }
1771
+ /**
1772
+ * Get user's 5A score
1773
+ */
1774
+ async getScore(user) {
1775
+ const target = user || this.client.publicKey;
1776
+ if (!target) {
1777
+ throw new Error("No user specified and wallet not connected");
1778
+ }
1779
+ try {
1780
+ const scorePda = this.client.pdas.getUserScore(target);
1781
+ const accountInfo = await this.client.connection.connection.getAccountInfo(scorePda);
1782
+ if (!accountInfo) {
1783
+ return null;
1784
+ }
1785
+ const data = accountInfo.data;
1786
+ return {
1787
+ user: new import_web39.PublicKey(data.slice(8, 40)),
1788
+ authenticity: data.readUInt16LE(40),
1789
+ accuracy: data.readUInt16LE(42),
1790
+ agility: data.readUInt16LE(44),
1791
+ activity: data.readUInt16LE(46),
1792
+ approved: data.readUInt16LE(48),
1793
+ compositeScore: data.readUInt16LE(50),
1794
+ lastUpdated: new import_anchor8.BN(data.slice(52, 60), "le"),
1795
+ isPrivate: data[60] !== 0
1796
+ };
1797
+ } catch {
1798
+ return null;
1799
+ }
1800
+ }
1801
+ /**
1802
+ * Format score as percentage
1803
+ */
1804
+ formatScore(score) {
1805
+ return `${(score / 100).toFixed(2)}%`;
1806
+ }
1807
+ /**
1808
+ * Get score tier
1809
+ */
1810
+ getScoreTier(composite) {
1811
+ if (composite >= 8e3) return "Excellent";
1812
+ if (composite >= 6e3) return "Good";
1813
+ if (composite >= 4e3) return "Average";
1814
+ if (composite >= 2e3) return "Below Average";
1815
+ return "Low";
1816
+ }
1817
+ /**
1818
+ * Get reward multiplier for score
1819
+ */
1820
+ getRewardMultiplier(composite) {
1821
+ if (composite >= 8e3) return FIVE_A_CONSTANTS.scoreMultipliers["80-100"];
1822
+ if (composite >= 6e3) return FIVE_A_CONSTANTS.scoreMultipliers["60-80"];
1823
+ if (composite >= 4e3) return FIVE_A_CONSTANTS.scoreMultipliers["40-60"];
1824
+ if (composite >= 2e3) return FIVE_A_CONSTANTS.scoreMultipliers["20-40"];
1825
+ return FIVE_A_CONSTANTS.scoreMultipliers["0-20"];
1826
+ }
1827
+ /**
1828
+ * Get score breakdown
1829
+ */
1830
+ getScoreBreakdown(score) {
1831
+ const weights = FIVE_A_CONSTANTS.scoreWeights;
1832
+ return [
1833
+ {
1834
+ component: "A1 - Authenticity",
1835
+ description: "Are you a real person?",
1836
+ score: this.formatScore(score.authenticity),
1837
+ weight: weights.authenticity,
1838
+ contribution: this.formatScore(score.authenticity * weights.authenticity / 100)
1839
+ },
1840
+ {
1841
+ component: "A2 - Accuracy",
1842
+ description: "Is your content quality?",
1843
+ score: this.formatScore(score.accuracy),
1844
+ weight: weights.accuracy,
1845
+ contribution: this.formatScore(score.accuracy * weights.accuracy / 100)
1846
+ },
1847
+ {
1848
+ component: "A3 - Agility",
1849
+ description: "Are you fast?",
1850
+ score: this.formatScore(score.agility),
1851
+ weight: weights.agility,
1852
+ contribution: this.formatScore(score.agility * weights.agility / 100)
1853
+ },
1854
+ {
1855
+ component: "A4 - Activity",
1856
+ description: "Do you show up daily?",
1857
+ score: this.formatScore(score.activity),
1858
+ weight: weights.activity,
1859
+ contribution: this.formatScore(score.activity * weights.activity / 100)
1860
+ },
1861
+ {
1862
+ component: "A5 - Approved",
1863
+ description: "Does the community like you?",
1864
+ score: this.formatScore(score.approved),
1865
+ weight: weights.approved,
1866
+ contribution: this.formatScore(score.approved * weights.approved / 100)
1867
+ }
1868
+ ];
1869
+ }
1870
+ /**
1871
+ * Calculate max vouches for score
1872
+ */
1873
+ getMaxVouches(composite) {
1874
+ if (composite >= 9e3) return 20;
1875
+ if (composite >= 8e3) return 15;
1876
+ if (composite >= 7e3) return 10;
1877
+ if (composite >= 6e3) return 7;
1878
+ if (composite >= 5e3) return 5;
1879
+ if (composite >= 4e3) return 3;
1880
+ return 2;
1881
+ }
1882
+ /**
1883
+ * Check if user can vouch for another
1884
+ */
1885
+ async canVouchFor(target) {
1886
+ if (!this.client.publicKey) {
1887
+ return { canVouch: false, reason: "Wallet not connected" };
1888
+ }
1889
+ if (this.client.publicKey.equals(target)) {
1890
+ return { canVouch: false, reason: "Cannot vouch for yourself" };
1891
+ }
1892
+ const myScore = await this.getScore();
1893
+ if (!myScore) {
1894
+ return { canVouch: false, reason: "No 5A score found" };
1895
+ }
1896
+ if (myScore.compositeScore < 6e3) {
1897
+ return { canVouch: false, reason: "Score too low to vouch (min 60%)" };
1898
+ }
1899
+ return { canVouch: true };
1900
+ }
1901
+ /**
1902
+ * Get score improvement suggestions
1903
+ */
1904
+ getImprovementSuggestions(score) {
1905
+ const suggestions = [];
1906
+ if (score.authenticity < 6e3) {
1907
+ suggestions.push("Complete identity verification to improve Authenticity (A1)");
1908
+ }
1909
+ if (score.accuracy < 6e3) {
1910
+ suggestions.push("Create quality content to improve Accuracy (A2)");
1911
+ }
1912
+ if (score.agility < 6e3) {
1913
+ suggestions.push("Respond faster to improve Agility (A3)");
1914
+ }
1915
+ if (score.activity < 6e3) {
1916
+ suggestions.push("Engage daily with content to improve Activity (A4)");
1917
+ }
1918
+ if (score.approved < 6e3) {
1919
+ suggestions.push("Get vouched by high-score users to improve Approved (A5)");
1920
+ }
1921
+ return suggestions;
1922
+ }
1923
+ // ============ Transaction Building ============
1924
+ /**
1925
+ * Build vouch transaction
1926
+ */
1927
+ async buildVouchTransaction(target) {
1928
+ if (!this.client.publicKey) {
1929
+ throw new Error("Wallet not connected");
1930
+ }
1931
+ const { canVouch, reason } = await this.canVouchFor(target);
1932
+ if (!canVouch) {
1933
+ throw new Error(reason);
1934
+ }
1935
+ const tx = new import_web39.Transaction();
1936
+ return tx;
1937
+ }
1938
+ };
1939
+
1940
+ // src/content/index.ts
1941
+ var import_web310 = require("@solana/web3.js");
1942
+ var import_anchor9 = require("@coral-xyz/anchor");
1943
+ var ContentClient = class {
1944
+ constructor(client) {
1945
+ this.client = client;
1946
+ }
1947
+ /**
1948
+ * Get content record
1949
+ */
1950
+ async getContent(contentId) {
1951
+ try {
1952
+ const contentPda = this.client.pdas.getContentRecord(contentId);
1953
+ const accountInfo = await this.client.connection.connection.getAccountInfo(contentPda);
1954
+ if (!accountInfo) {
1955
+ return null;
1956
+ }
1957
+ const data = accountInfo.data;
1958
+ return {
1959
+ contentId: new Uint8Array(data.slice(8, 40)),
1960
+ creator: new import_web310.PublicKey(data.slice(40, 72)),
1961
+ contentHash: new Uint8Array(data.slice(72, 104)),
1962
+ state: data[104],
1963
+ createdAt: new import_anchor9.BN(data.slice(105, 113), "le"),
1964
+ editCount: data.readUInt16LE(113),
1965
+ tips: new import_anchor9.BN(data.slice(115, 123), "le"),
1966
+ engagementScore: new import_anchor9.BN(data.slice(123, 131), "le")
1967
+ };
1968
+ } catch {
1969
+ return null;
1970
+ }
1971
+ }
1972
+ /**
1973
+ * Get user's energy
1974
+ */
1975
+ async getEnergy(user) {
1976
+ const target = user || this.client.publicKey;
1977
+ if (!target) {
1978
+ throw new Error("No user specified and wallet not connected");
1979
+ }
1980
+ try {
1981
+ const energyPda = this.client.pdas.getUserEnergy(target);
1982
+ const accountInfo = await this.client.connection.connection.getAccountInfo(energyPda);
1983
+ if (!accountInfo) {
1984
+ return null;
1985
+ }
1986
+ const data = accountInfo.data;
1987
+ return {
1988
+ user: new import_web310.PublicKey(data.slice(8, 40)),
1989
+ currentEnergy: data.readUInt16LE(40),
1990
+ maxEnergy: data.readUInt16LE(42),
1991
+ lastRegenTime: new import_anchor9.BN(data.slice(44, 52), "le"),
1992
+ tier: data[52]
1993
+ };
1994
+ } catch {
1995
+ return null;
1996
+ }
1997
+ }
1998
+ /**
1999
+ * Get content state name
2000
+ */
2001
+ getStateName(state) {
2002
+ const states = ["Active", "Hidden", "Deleted", "Flagged"];
2003
+ return states[state] || "Unknown";
2004
+ }
2005
+ /**
2006
+ * Calculate regenerated energy
2007
+ */
2008
+ calculateRegenEnergy(energy) {
2009
+ const now = getCurrentTimestamp();
2010
+ const secondsSinceRegen = now - energy.lastRegenTime.toNumber();
2011
+ const hoursSinceRegen = secondsSinceRegen / 3600;
2012
+ const regenAmount = Math.floor(hoursSinceRegen * CONTENT_CONSTANTS.energyRegenRate);
2013
+ const newEnergy = Math.min(
2014
+ energy.maxEnergy,
2015
+ energy.currentEnergy + regenAmount
2016
+ );
2017
+ return newEnergy;
2018
+ }
2019
+ /**
2020
+ * Get time until next energy
2021
+ */
2022
+ getTimeUntilNextEnergy(energy) {
2023
+ if (energy.currentEnergy >= energy.maxEnergy) {
2024
+ return 0;
2025
+ }
2026
+ const now = getCurrentTimestamp();
2027
+ const secondsSinceRegen = now - energy.lastRegenTime.toNumber();
2028
+ const secondsPerEnergy = 3600 / CONTENT_CONSTANTS.energyRegenRate;
2029
+ const nextRegenIn = secondsPerEnergy - secondsSinceRegen % secondsPerEnergy;
2030
+ return Math.max(0, Math.ceil(nextRegenIn));
2031
+ }
2032
+ /**
2033
+ * Get time until full energy
2034
+ */
2035
+ getTimeUntilFull(energy) {
2036
+ const currentEnergy = this.calculateRegenEnergy(energy);
2037
+ if (currentEnergy >= energy.maxEnergy) {
2038
+ return 0;
2039
+ }
2040
+ const energyNeeded = energy.maxEnergy - currentEnergy;
2041
+ const secondsPerEnergy = 3600 / CONTENT_CONSTANTS.energyRegenRate;
2042
+ return Math.ceil(energyNeeded * secondsPerEnergy);
2043
+ }
2044
+ /**
2045
+ * Check if user can create content
2046
+ */
2047
+ async canCreateContent(user) {
2048
+ const energy = await this.getEnergy(user);
2049
+ if (!energy) {
2050
+ return { canCreate: false, reason: "Energy account not found" };
2051
+ }
2052
+ const currentEnergy = this.calculateRegenEnergy(energy);
2053
+ const energyNeeded = CONTENT_CONSTANTS.createCost;
2054
+ if (currentEnergy < energyNeeded) {
2055
+ return {
2056
+ canCreate: false,
2057
+ reason: `Insufficient energy (${currentEnergy}/${energyNeeded})`,
2058
+ energyNeeded,
2059
+ energyAvailable: currentEnergy
2060
+ };
2061
+ }
2062
+ return { canCreate: true, energyNeeded, energyAvailable: currentEnergy };
2063
+ }
2064
+ /**
2065
+ * Check if user can edit content
2066
+ */
2067
+ async canEditContent(contentId, user) {
2068
+ const target = user || this.client.publicKey;
2069
+ if (!target) {
2070
+ return { canEdit: false, reason: "Wallet not connected" };
2071
+ }
2072
+ const content = await this.getContent(contentId);
2073
+ if (!content) {
2074
+ return { canEdit: false, reason: "Content not found" };
2075
+ }
2076
+ if (!content.creator.equals(target)) {
2077
+ return { canEdit: false, reason: "Not content creator" };
2078
+ }
2079
+ if (content.state === 2) {
2080
+ return { canEdit: false, reason: "Content is deleted" };
2081
+ }
2082
+ const energy = await this.getEnergy(target);
2083
+ if (!energy) {
2084
+ return { canEdit: false, reason: "Energy account not found" };
2085
+ }
2086
+ const currentEnergy = this.calculateRegenEnergy(energy);
2087
+ if (currentEnergy < CONTENT_CONSTANTS.editCost) {
2088
+ return { canEdit: false, reason: "Insufficient energy" };
2089
+ }
2090
+ return { canEdit: true };
2091
+ }
2092
+ /**
2093
+ * Get content stats
2094
+ */
2095
+ async getContentStats(contentId) {
2096
+ const content = await this.getContent(contentId);
2097
+ if (!content) {
2098
+ throw new Error("Content not found");
2099
+ }
2100
+ const now = getCurrentTimestamp();
2101
+ const age = now - content.createdAt.toNumber();
2102
+ return {
2103
+ tips: formatVCoin(content.tips),
2104
+ engagementScore: content.engagementScore.toString(),
2105
+ editCount: content.editCount,
2106
+ state: this.getStateName(content.state),
2107
+ age
2108
+ };
2109
+ }
2110
+ // ============ Transaction Building ============
2111
+ /**
2112
+ * Build create content transaction
2113
+ */
2114
+ async buildCreateContentTransaction(contentHash) {
2115
+ if (!this.client.publicKey) {
2116
+ throw new Error("Wallet not connected");
2117
+ }
2118
+ const { canCreate, reason } = await this.canCreateContent();
2119
+ if (!canCreate) {
2120
+ throw new Error(reason);
2121
+ }
2122
+ if (contentHash.length !== 32) {
2123
+ throw new Error("Content hash must be 32 bytes");
2124
+ }
2125
+ const tx = new import_web310.Transaction();
2126
+ return tx;
2127
+ }
2128
+ /**
2129
+ * Build edit content transaction
2130
+ */
2131
+ async buildEditContentTransaction(contentId, newContentHash) {
2132
+ if (!this.client.publicKey) {
2133
+ throw new Error("Wallet not connected");
2134
+ }
2135
+ const { canEdit, reason } = await this.canEditContent(contentId);
2136
+ if (!canEdit) {
2137
+ throw new Error(reason);
2138
+ }
2139
+ const tx = new import_web310.Transaction();
2140
+ return tx;
2141
+ }
2142
+ /**
2143
+ * Build delete content transaction
2144
+ */
2145
+ async buildDeleteContentTransaction(contentId) {
2146
+ if (!this.client.publicKey) {
2147
+ throw new Error("Wallet not connected");
2148
+ }
2149
+ const content = await this.getContent(contentId);
2150
+ if (!content) {
2151
+ throw new Error("Content not found");
2152
+ }
2153
+ if (!content.creator.equals(this.client.publicKey)) {
2154
+ throw new Error("Not content creator");
2155
+ }
2156
+ const tx = new import_web310.Transaction();
2157
+ return tx;
2158
+ }
2159
+ };
2160
+
2161
+ // src/client.ts
2162
+ var import_web311 = require("@solana/web3.js");
2163
+ var import_anchor10 = require("@coral-xyz/anchor");
2164
+ var import_spl_token = require("@solana/spl-token");
2165
+ var ViWoClient = class {
2166
+ constructor(config) {
2167
+ if (config.connection instanceof import_web311.Connection) {
2168
+ this.connection = new ViWoConnection({
2169
+ endpoint: config.connection.rpcEndpoint,
2170
+ commitment: "confirmed"
2171
+ });
2172
+ } else {
2173
+ this.connection = new ViWoConnection(config.connection);
2174
+ }
2175
+ this.wallet = config.wallet || null;
2176
+ this.programIds = {
2177
+ ...PROGRAM_IDS,
2178
+ ...config.programIds
2179
+ };
2180
+ this.pdas = new PDAs(this.programIds);
2181
+ this.staking = new StakingClient(this);
2182
+ this.governance = new GovernanceClient(this);
2183
+ this.rewards = new RewardsClient(this);
2184
+ this.vilink = new ViLinkClient(this);
2185
+ this.gasless = new GaslessClient(this);
2186
+ this.identity = new IdentityClient(this);
2187
+ this.fivea = new FiveAClient(this);
2188
+ this.content = new ContentClient(this);
2189
+ }
2190
+ /**
2191
+ * Get the wallet public key
2192
+ */
2193
+ get publicKey() {
2194
+ return this.wallet?.publicKey || null;
2195
+ }
2196
+ /**
2197
+ * Check if wallet is connected
2198
+ */
2199
+ get isConnected() {
2200
+ return this.wallet !== null && this.wallet.publicKey !== null;
2201
+ }
2202
+ /**
2203
+ * Set wallet adapter
2204
+ */
2205
+ setWallet(wallet) {
2206
+ this.wallet = wallet;
2207
+ this.staking = new StakingClient(this);
2208
+ this.governance = new GovernanceClient(this);
2209
+ this.rewards = new RewardsClient(this);
2210
+ this.vilink = new ViLinkClient(this);
2211
+ this.gasless = new GaslessClient(this);
2212
+ this.identity = new IdentityClient(this);
2213
+ this.fivea = new FiveAClient(this);
2214
+ this.content = new ContentClient(this);
2215
+ }
2216
+ /**
2217
+ * Get Anchor provider
2218
+ */
2219
+ getProvider() {
2220
+ if (!this.wallet || !this.wallet.publicKey) {
2221
+ return null;
2222
+ }
2223
+ return new import_anchor10.AnchorProvider(
2224
+ this.connection.connection,
2225
+ this.wallet,
2226
+ { commitment: this.connection.commitment }
2227
+ );
2228
+ }
2229
+ /**
2230
+ * Send and confirm transaction
2231
+ */
2232
+ async sendTransaction(tx) {
2233
+ if (!this.wallet) {
2234
+ throw new Error("Wallet not connected");
2235
+ }
2236
+ const { blockhash, lastValidBlockHeight } = await this.connection.connection.getLatestBlockhash();
2237
+ tx.recentBlockhash = blockhash;
2238
+ tx.feePayer = this.wallet.publicKey;
2239
+ const signedTx = await this.wallet.signTransaction(tx);
2240
+ const signature = await this.connection.connection.sendRawTransaction(
2241
+ signedTx.serialize()
2242
+ );
2243
+ await this.connection.connection.confirmTransaction({
2244
+ signature,
2245
+ blockhash,
2246
+ lastValidBlockHeight
2247
+ });
2248
+ return signature;
2249
+ }
2250
+ /**
2251
+ * Get VCoin balance
2252
+ */
2253
+ async getVCoinBalance(user) {
2254
+ const target = user || this.publicKey;
2255
+ if (!target) {
2256
+ throw new Error("No user specified and wallet not connected");
2257
+ }
2258
+ try {
2259
+ const tokenAccounts = await this.connection.connection.getTokenAccountsByOwner(
2260
+ target,
2261
+ { programId: import_spl_token.TOKEN_2022_PROGRAM_ID }
2262
+ );
2263
+ let balance = new import_anchor10.BN(0);
2264
+ for (const { account } of tokenAccounts.value) {
2265
+ const data = account.data;
2266
+ const amount = data.slice(64, 72);
2267
+ balance = balance.add(new import_anchor10.BN(amount, "le"));
2268
+ }
2269
+ return balance;
2270
+ } catch {
2271
+ return new import_anchor10.BN(0);
2272
+ }
2273
+ }
2274
+ /**
2275
+ * Get veVCoin balance
2276
+ */
2277
+ async getVeVCoinBalance(user) {
2278
+ const target = user || this.publicKey;
2279
+ if (!target) {
2280
+ throw new Error("No user specified and wallet not connected");
2281
+ }
2282
+ try {
2283
+ const stakeData = await this.staking.getUserStake(target);
2284
+ return stakeData?.vevcoinBalance || new import_anchor10.BN(0);
2285
+ } catch {
2286
+ return new import_anchor10.BN(0);
2287
+ }
2288
+ }
2289
+ /**
2290
+ * Check connection health
2291
+ */
2292
+ async healthCheck() {
2293
+ try {
2294
+ const [connected, slot] = await Promise.all([
2295
+ this.connection.isHealthy(),
2296
+ this.connection.getSlot()
2297
+ ]);
2298
+ const blockTime = await this.connection.getBlockTime();
2299
+ return { connected, slot, blockTime };
2300
+ } catch {
2301
+ return { connected: false, slot: null, blockTime: null };
2302
+ }
2303
+ }
2304
+ };
2305
+ // Annotate the CommonJS export names for ESM import in node:
2306
+ 0 && (module.exports = {
2307
+ ACTION_SCOPES,
2308
+ ActionType,
2309
+ BN,
2310
+ CONTENT_CONSTANTS,
2311
+ ContentClient,
2312
+ ContentState,
2313
+ FIVE_A_CONSTANTS,
2314
+ FeeMethod,
2315
+ FiveAClient,
2316
+ GASLESS_CONSTANTS,
2317
+ GOVERNANCE_CONSTANTS,
2318
+ GaslessClient,
2319
+ GovernanceClient,
2320
+ IdentityClient,
2321
+ LOCK_DURATIONS,
2322
+ PDAs,
2323
+ PROGRAM_IDS,
2324
+ ProposalStatus,
2325
+ RewardsClient,
2326
+ SEEDS,
2327
+ SSCRE_CONSTANTS,
2328
+ STAKING_TIERS,
2329
+ StakingClient,
2330
+ StakingTier,
2331
+ TransactionBuilder,
2332
+ VCOIN_DECIMALS,
2333
+ VCOIN_INITIAL_CIRCULATING,
2334
+ VCOIN_TOTAL_SUPPLY,
2335
+ VEVCOIN_DECIMALS,
2336
+ VILINK_CONSTANTS,
2337
+ VerificationLevel,
2338
+ ViLinkClient,
2339
+ ViWoClient,
2340
+ ViWoConnection,
2341
+ dateToTimestamp,
2342
+ formatVCoin,
2343
+ getCurrentTimestamp,
2344
+ parseVCoin,
2345
+ timestampToDate
2346
+ });