@viwoapp/sdk 0.1.8 → 2.0.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 +581 -427
- package/dist/index.d.mts +268 -12
- package/dist/index.d.ts +268 -12
- package/dist/index.js +275 -17
- package/dist/index.mjs +275 -17
- package/package.json +82 -82
package/dist/index.mjs
CHANGED
|
@@ -204,9 +204,22 @@ var GOVERNANCE_CONSTANTS = {
|
|
|
204
204
|
vetoWindow: 24 * 3600,
|
|
205
205
|
// 1 day
|
|
206
206
|
quorumBps: 400,
|
|
207
|
-
// 4%
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
// 4% (C-03: abstains no longer count toward quorum)
|
|
208
|
+
/** Authority transfer timelock (H-02) */
|
|
209
|
+
authorityTransferTimelock: 24 * 3600,
|
|
210
|
+
// 24 hours
|
|
211
|
+
/** ZK private voting constants */
|
|
212
|
+
zk: {
|
|
213
|
+
/** Vote validity proof size (3 OR proofs + 1 sum proof) */
|
|
214
|
+
voteProofSize: 352,
|
|
215
|
+
/** ElGamal ciphertext size (R || C) */
|
|
216
|
+
ciphertextSize: 64,
|
|
217
|
+
/** Max committee members */
|
|
218
|
+
maxCommitteeSize: 5,
|
|
219
|
+
/** Account sizes */
|
|
220
|
+
privateVotingConfigSize: 680,
|
|
221
|
+
decryptionShareSize: 242
|
|
222
|
+
}
|
|
210
223
|
};
|
|
211
224
|
var SECURITY_CONSTANTS = {
|
|
212
225
|
// H-02: Two-step authority transfer
|
|
@@ -241,8 +254,21 @@ var SECURITY_CONSTANTS = {
|
|
|
241
254
|
// H-NEW-02: Max proof levels (supports 4B+ users)
|
|
242
255
|
maxEpochBitmap: 1023,
|
|
243
256
|
// H-NEW-04: Max epoch with bitmap storage (85+ years)
|
|
244
|
-
votingPowerVerifiedOnChain: true
|
|
257
|
+
votingPowerVerifiedOnChain: true,
|
|
245
258
|
// C-NEW-01: Params read from chain, not passed
|
|
259
|
+
// Audit remediation additions
|
|
260
|
+
/** H-AUDIT-12: Maximum concurrent sessions per user */
|
|
261
|
+
maxSessionsPerUser: 5,
|
|
262
|
+
/** C-AUDIT-15: Maximum day delta for daily budget reset (clock skew protection) */
|
|
263
|
+
maxDayDelta: 2,
|
|
264
|
+
/** H-AUDIT-09: Maximum daily activity score for transfer hook */
|
|
265
|
+
maxDailyActivityScore: 5e3,
|
|
266
|
+
/** M-AUDIT-10: Wash flag decay period (7 days) */
|
|
267
|
+
washFlagDecayPeriod: 7 * 24 * 3600,
|
|
268
|
+
/** M-18: Maximum vouch age before expiry (1 year) */
|
|
269
|
+
maxVouchAge: 365 * 24 * 3600,
|
|
270
|
+
/** C-AUDIT-11: Valid content energy tiers (1-4) */
|
|
271
|
+
maxContentTier: 4
|
|
246
272
|
};
|
|
247
273
|
var VALID_URI_PREFIXES = ["ipfs://", "https://", "ar://"];
|
|
248
274
|
var MAX_URI_LENGTH = 128;
|
|
@@ -679,6 +705,10 @@ var StakingClient = class {
|
|
|
679
705
|
}
|
|
680
706
|
/**
|
|
681
707
|
* Get tier name
|
|
708
|
+
*
|
|
709
|
+
* M-05: The on-chain update_tier instruction will reject no-op tier updates
|
|
710
|
+
* with TierUnchanged error. Only call updateTier when the user's stake amount
|
|
711
|
+
* actually qualifies for a different tier.
|
|
682
712
|
*/
|
|
683
713
|
getTierName(tier) {
|
|
684
714
|
const names = ["None", "Bronze", "Silver", "Gold", "Platinum"];
|
|
@@ -790,11 +820,14 @@ var GovernanceClient = class {
|
|
|
790
820
|
if (!accountInfo) {
|
|
791
821
|
return null;
|
|
792
822
|
}
|
|
823
|
+
const data = accountInfo.data;
|
|
793
824
|
return {
|
|
794
|
-
authority: new PublicKey4(
|
|
795
|
-
proposalCount: new BN3(
|
|
796
|
-
vevcoinMint: new PublicKey4(
|
|
797
|
-
paused:
|
|
825
|
+
authority: new PublicKey4(data.slice(8, 40)),
|
|
826
|
+
proposalCount: new BN3(data.slice(40, 48), "le"),
|
|
827
|
+
vevcoinMint: new PublicKey4(data.slice(48, 80)),
|
|
828
|
+
paused: data[80] !== 0,
|
|
829
|
+
pendingAuthority: new PublicKey4(data.slice(81, 113)),
|
|
830
|
+
pendingAuthorityActivatedAt: new BN3(data.slice(113, 121), "le")
|
|
798
831
|
};
|
|
799
832
|
} catch {
|
|
800
833
|
return null;
|
|
@@ -867,7 +900,11 @@ var GovernanceClient = class {
|
|
|
867
900
|
proposal: new PublicKey4(data.slice(40, 72)),
|
|
868
901
|
votePower: new BN3(data.slice(72, 80), "le"),
|
|
869
902
|
support: data[80] !== 0,
|
|
870
|
-
votedAt: new BN3(data.slice(81, 89), "le")
|
|
903
|
+
votedAt: new BN3(data.slice(81, 89), "le"),
|
|
904
|
+
// Private vote ciphertexts (if present, at byte offsets after public vote fields)
|
|
905
|
+
ctFor: new Uint8Array(data.slice(89, 153)),
|
|
906
|
+
ctAgainst: new Uint8Array(data.slice(153, 217)),
|
|
907
|
+
ctAbstain: new Uint8Array(data.slice(217, 281))
|
|
871
908
|
};
|
|
872
909
|
} catch {
|
|
873
910
|
return null;
|
|
@@ -882,6 +919,9 @@ var GovernanceClient = class {
|
|
|
882
919
|
}
|
|
883
920
|
/**
|
|
884
921
|
* Calculate user's voting power
|
|
922
|
+
*
|
|
923
|
+
* @note M-01 fix: 5A boost formula is now `1000 + ((five_a_score * 100) / 1000)`
|
|
924
|
+
* to fix precision loss for small scores.
|
|
885
925
|
*/
|
|
886
926
|
async getVotingPower(user) {
|
|
887
927
|
const target = user || this.client.publicKey;
|
|
@@ -924,6 +964,9 @@ var GovernanceClient = class {
|
|
|
924
964
|
}
|
|
925
965
|
/**
|
|
926
966
|
* Get proposal progress
|
|
967
|
+
*
|
|
968
|
+
* @note C-03: Quorum is now calculated as votesFor + votesAgainst only.
|
|
969
|
+
* Abstains do NOT count toward quorum.
|
|
927
970
|
*/
|
|
928
971
|
async getProposalProgress(proposalId) {
|
|
929
972
|
const proposal = await this.getProposal(proposalId);
|
|
@@ -947,7 +990,7 @@ var GovernanceClient = class {
|
|
|
947
990
|
timeRemaining
|
|
948
991
|
};
|
|
949
992
|
}
|
|
950
|
-
// ============ Transaction Building ============
|
|
993
|
+
// ============ Transaction Building (Public Voting) ============
|
|
951
994
|
/**
|
|
952
995
|
* Build create proposal transaction
|
|
953
996
|
*/
|
|
@@ -963,12 +1006,12 @@ var GovernanceClient = class {
|
|
|
963
1006
|
return tx;
|
|
964
1007
|
}
|
|
965
1008
|
/**
|
|
966
|
-
* Build vote transaction
|
|
967
|
-
*
|
|
968
|
-
* @note v2.8.0 (C-NEW-01): Voting power parameters (vevcoin_balance, five_a_score, tier)
|
|
1009
|
+
* Build vote transaction (public)
|
|
1010
|
+
*
|
|
1011
|
+
* @note v2.8.0 (C-NEW-01): Voting power parameters (vevcoin_balance, five_a_score, tier)
|
|
969
1012
|
* are now read from on-chain state, not passed as parameters. This prevents vote manipulation.
|
|
970
1013
|
* The transaction only needs: proposal_id and choice (VoteChoice enum)
|
|
971
|
-
*
|
|
1014
|
+
*
|
|
972
1015
|
* @param proposalId - The proposal to vote on
|
|
973
1016
|
* @param support - true = For, false = Against (use VoteChoice for more options)
|
|
974
1017
|
*/
|
|
@@ -998,6 +1041,148 @@ var GovernanceClient = class {
|
|
|
998
1041
|
const tx = new Transaction3();
|
|
999
1042
|
return tx;
|
|
1000
1043
|
}
|
|
1044
|
+
// ============ ZK Private Voting ============
|
|
1045
|
+
/**
|
|
1046
|
+
* Build cast private vote transaction
|
|
1047
|
+
*
|
|
1048
|
+
* Uses Twisted ElGamal encryption on Ristretto255 with compressed sigma proofs.
|
|
1049
|
+
* The voter encrypts their choice into 3 ciphertexts (for/against/abstain) and
|
|
1050
|
+
* generates a validity proof that exactly one ciphertext encrypts their weight.
|
|
1051
|
+
*
|
|
1052
|
+
* Use the `zk-voting-sdk` crate to generate ciphertexts and proofs off-chain:
|
|
1053
|
+
* ```rust
|
|
1054
|
+
* let (ct_for, ct_against, ct_abstain, proof) = encrypt_and_prove(&pubkey, choice, weight);
|
|
1055
|
+
* ```
|
|
1056
|
+
*
|
|
1057
|
+
* @param params - Private vote parameters with ciphertexts and proof
|
|
1058
|
+
*/
|
|
1059
|
+
async buildCastPrivateVoteTransaction(params) {
|
|
1060
|
+
if (!this.client.publicKey) {
|
|
1061
|
+
throw new Error("Wallet not connected");
|
|
1062
|
+
}
|
|
1063
|
+
if (params.ctFor.length !== GOVERNANCE_CONSTANTS.zk.ciphertextSize) {
|
|
1064
|
+
throw new Error(`ctFor must be ${GOVERNANCE_CONSTANTS.zk.ciphertextSize} bytes`);
|
|
1065
|
+
}
|
|
1066
|
+
if (params.ctAgainst.length !== GOVERNANCE_CONSTANTS.zk.ciphertextSize) {
|
|
1067
|
+
throw new Error(`ctAgainst must be ${GOVERNANCE_CONSTANTS.zk.ciphertextSize} bytes`);
|
|
1068
|
+
}
|
|
1069
|
+
if (params.ctAbstain.length !== GOVERNANCE_CONSTANTS.zk.ciphertextSize) {
|
|
1070
|
+
throw new Error(`ctAbstain must be ${GOVERNANCE_CONSTANTS.zk.ciphertextSize} bytes`);
|
|
1071
|
+
}
|
|
1072
|
+
if (params.proofData.length !== GOVERNANCE_CONSTANTS.zk.voteProofSize) {
|
|
1073
|
+
throw new Error(`proofData must be ${GOVERNANCE_CONSTANTS.zk.voteProofSize} bytes`);
|
|
1074
|
+
}
|
|
1075
|
+
const hasVoted = await this.hasVoted(params.proposalId);
|
|
1076
|
+
if (hasVoted) {
|
|
1077
|
+
throw new Error("Already voted on this proposal");
|
|
1078
|
+
}
|
|
1079
|
+
const tx = new Transaction3();
|
|
1080
|
+
return tx;
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Build enable private voting transaction
|
|
1084
|
+
*
|
|
1085
|
+
* Called by the governance authority to enable ZK private voting on a proposal.
|
|
1086
|
+
* Requires specifying the decryption committee and their ElGamal public keys.
|
|
1087
|
+
*
|
|
1088
|
+
* @param params - Private voting configuration
|
|
1089
|
+
*/
|
|
1090
|
+
async buildEnablePrivateVotingTransaction(params) {
|
|
1091
|
+
if (!this.client.publicKey) {
|
|
1092
|
+
throw new Error("Wallet not connected");
|
|
1093
|
+
}
|
|
1094
|
+
if (params.encryptionPubkey.length !== 32) {
|
|
1095
|
+
throw new Error("encryptionPubkey must be 32 bytes (Ristretto255 point)");
|
|
1096
|
+
}
|
|
1097
|
+
if (params.committeeSize > GOVERNANCE_CONSTANTS.zk.maxCommitteeSize) {
|
|
1098
|
+
throw new Error(`Committee size exceeds max of ${GOVERNANCE_CONSTANTS.zk.maxCommitteeSize}`);
|
|
1099
|
+
}
|
|
1100
|
+
if (params.decryptionThreshold > params.committeeSize) {
|
|
1101
|
+
throw new Error("Threshold cannot exceed committee size");
|
|
1102
|
+
}
|
|
1103
|
+
for (let i = 0; i < params.committeeSize; i++) {
|
|
1104
|
+
if (!params.committeeElgamalPubkeys[i] || params.committeeElgamalPubkeys[i].length !== 32) {
|
|
1105
|
+
throw new Error(`Committee member ${i} ElGamal pubkey must be 32 bytes`);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
const tx = new Transaction3();
|
|
1109
|
+
return tx;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Build submit decryption share transaction
|
|
1113
|
+
*
|
|
1114
|
+
* Called by a committee member during the reveal phase.
|
|
1115
|
+
* Each member computes partial decryptions and a DLEQ proof off-chain:
|
|
1116
|
+
* ```rust
|
|
1117
|
+
* let partial = generate_partial_decryption(&secret_share, &pk, &r_for, &r_against, &r_abstain);
|
|
1118
|
+
* ```
|
|
1119
|
+
*
|
|
1120
|
+
* @param params - Decryption share with DLEQ proof
|
|
1121
|
+
*/
|
|
1122
|
+
async buildSubmitDecryptionShareTransaction(params) {
|
|
1123
|
+
if (!this.client.publicKey) {
|
|
1124
|
+
throw new Error("Wallet not connected");
|
|
1125
|
+
}
|
|
1126
|
+
const fields = [
|
|
1127
|
+
{ name: "partialFor", value: params.partialFor },
|
|
1128
|
+
{ name: "partialAgainst", value: params.partialAgainst },
|
|
1129
|
+
{ name: "partialAbstain", value: params.partialAbstain },
|
|
1130
|
+
{ name: "dleqChallenge", value: params.dleqChallenge },
|
|
1131
|
+
{ name: "dleqResponse", value: params.dleqResponse }
|
|
1132
|
+
];
|
|
1133
|
+
for (const { name, value } of fields) {
|
|
1134
|
+
if (value.length !== 32) {
|
|
1135
|
+
throw new Error(`${name} must be 32 bytes`);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
const tx = new Transaction3();
|
|
1139
|
+
return tx;
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1142
|
+
* Build aggregate revealed votes transaction (permissionless)
|
|
1143
|
+
*
|
|
1144
|
+
* Anyone can submit the aggregated tally since the on-chain program
|
|
1145
|
+
* cryptographically verifies: tally * H == C_sum - D for each category.
|
|
1146
|
+
* This prevents fabrication of results.
|
|
1147
|
+
*
|
|
1148
|
+
* Use the `zk-voting-sdk` to compute the tally off-chain:
|
|
1149
|
+
* ```rust
|
|
1150
|
+
* let lagrange = compute_lagrange_coefficients(&selected_indices);
|
|
1151
|
+
* let d = combine_partials(&lagrange, &partials);
|
|
1152
|
+
* let tally = recover_tally(&d, &accumulated_c, max_votes).unwrap();
|
|
1153
|
+
* ```
|
|
1154
|
+
*
|
|
1155
|
+
* @param params - Tally values and Lagrange coefficients
|
|
1156
|
+
*/
|
|
1157
|
+
async buildAggregateRevealedVotesTransaction(params) {
|
|
1158
|
+
for (let i = 0; i < params.lagrangeCoefficients.length; i++) {
|
|
1159
|
+
if (params.lagrangeCoefficients[i].length !== 32) {
|
|
1160
|
+
throw new Error(`Lagrange coefficient ${i} must be 32 bytes`);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
const tx = new Transaction3();
|
|
1164
|
+
return tx;
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Check if authority transfer timelock has elapsed (H-02)
|
|
1168
|
+
*/
|
|
1169
|
+
async canAcceptAuthority() {
|
|
1170
|
+
const config = await this.getConfig();
|
|
1171
|
+
if (!config) {
|
|
1172
|
+
return { canAccept: false, reason: "Config not found" };
|
|
1173
|
+
}
|
|
1174
|
+
if (!config.pendingAuthorityActivatedAt || config.pendingAuthorityActivatedAt.isZero()) {
|
|
1175
|
+
return { canAccept: false, reason: "No pending authority transfer" };
|
|
1176
|
+
}
|
|
1177
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1178
|
+
const timelockEnd = config.pendingAuthorityActivatedAt.toNumber() + GOVERNANCE_CONSTANTS.authorityTransferTimelock;
|
|
1179
|
+
if (now < timelockEnd) {
|
|
1180
|
+
const remaining = timelockEnd - now;
|
|
1181
|
+
const hours = Math.ceil(remaining / 3600);
|
|
1182
|
+
return { canAccept: false, reason: `Timelock: ${hours} hours remaining` };
|
|
1183
|
+
}
|
|
1184
|
+
return { canAccept: true };
|
|
1185
|
+
}
|
|
1001
1186
|
};
|
|
1002
1187
|
|
|
1003
1188
|
// src/rewards/index.ts
|
|
@@ -1137,9 +1322,16 @@ var RewardsClient = class {
|
|
|
1137
1322
|
}
|
|
1138
1323
|
/**
|
|
1139
1324
|
* Calculate gasless fee for claim
|
|
1325
|
+
*
|
|
1326
|
+
* C-05: Uses ceiling division to prevent fee rounding to zero on small amounts.
|
|
1327
|
+
* Formula: fee = ceil(amount * feeBps / 10000)
|
|
1140
1328
|
*/
|
|
1141
1329
|
calculateGaslessFee(amount) {
|
|
1142
|
-
const
|
|
1330
|
+
const numerator = amount.muln(SSCRE_CONSTANTS.gaslessFeeBps).addn(9999);
|
|
1331
|
+
let fee = numerator.divn(1e4);
|
|
1332
|
+
if (fee.gt(amount)) {
|
|
1333
|
+
fee = amount;
|
|
1334
|
+
}
|
|
1143
1335
|
return fee;
|
|
1144
1336
|
}
|
|
1145
1337
|
/**
|
|
@@ -1196,6 +1388,9 @@ var RewardsClient = class {
|
|
|
1196
1388
|
// ============ Transaction Building ============
|
|
1197
1389
|
/**
|
|
1198
1390
|
* Build claim rewards transaction
|
|
1391
|
+
*
|
|
1392
|
+
* H-NEW-02: Merkle proof size is limited to 32 levels (supports 4B+ users).
|
|
1393
|
+
* Proofs exceeding this limit will be rejected on-chain with MerkleProofTooLarge.
|
|
1199
1394
|
*/
|
|
1200
1395
|
async buildClaimTransaction(params) {
|
|
1201
1396
|
if (!this.client.publicKey) {
|
|
@@ -1204,6 +1399,9 @@ var RewardsClient = class {
|
|
|
1204
1399
|
if (params.amount.lt(new BN4(SSCRE_CONSTANTS.minClaimAmount * 1e9))) {
|
|
1205
1400
|
throw new Error(`Claim amount below minimum: ${SSCRE_CONSTANTS.minClaimAmount} VCoin`);
|
|
1206
1401
|
}
|
|
1402
|
+
if (params.merkleProof.length > 32) {
|
|
1403
|
+
throw new Error("Merkle proof exceeds maximum size of 32 levels");
|
|
1404
|
+
}
|
|
1207
1405
|
const hasClaimed = await this.hasClaimedEpoch(params.epoch);
|
|
1208
1406
|
if (hasClaimed) {
|
|
1209
1407
|
throw new Error("Already claimed for this epoch");
|
|
@@ -1365,9 +1563,16 @@ var ViLinkClient = class {
|
|
|
1365
1563
|
}
|
|
1366
1564
|
/**
|
|
1367
1565
|
* Calculate platform fee for tip
|
|
1566
|
+
*
|
|
1567
|
+
* C-06: Uses ceiling division to prevent fee rounding to zero on small amounts.
|
|
1568
|
+
* Formula: fee = ceil(amount * feeBps / 10000)
|
|
1368
1569
|
*/
|
|
1369
1570
|
calculateFee(amount) {
|
|
1370
|
-
const
|
|
1571
|
+
const numerator = amount.muln(VILINK_CONSTANTS.platformFeeBps).addn(9999);
|
|
1572
|
+
let fee = numerator.divn(1e4);
|
|
1573
|
+
if (fee.gt(amount)) {
|
|
1574
|
+
fee = amount;
|
|
1575
|
+
}
|
|
1371
1576
|
return {
|
|
1372
1577
|
fee,
|
|
1373
1578
|
net: amount.sub(fee)
|
|
@@ -1449,6 +1654,13 @@ var ViLinkClient = class {
|
|
|
1449
1654
|
* Build execute tip action transaction
|
|
1450
1655
|
* @param creator - The action creator's public key
|
|
1451
1656
|
* @param nonce - M-04: The action nonce (NOT timestamp)
|
|
1657
|
+
*
|
|
1658
|
+
* H-05: The on-chain handler validates that the executor's token account has
|
|
1659
|
+
* no active delegation (delegate is None or delegated_amount is 0).
|
|
1660
|
+
* This prevents delegated tokens from being spent without explicit approval.
|
|
1661
|
+
*
|
|
1662
|
+
* C-06: Platform fee uses ceiling division to prevent zero-fee exploitation on
|
|
1663
|
+
* small amounts.
|
|
1452
1664
|
*/
|
|
1453
1665
|
async buildExecuteTipAction(creator, nonce) {
|
|
1454
1666
|
if (!this.client.publicKey) {
|
|
@@ -1556,6 +1768,9 @@ var GaslessClient = class {
|
|
|
1556
1768
|
}
|
|
1557
1769
|
/**
|
|
1558
1770
|
* Get user gasless statistics
|
|
1771
|
+
*
|
|
1772
|
+
* H-AUDIT-12: Now includes active_sessions field for per-user session limit tracking.
|
|
1773
|
+
* The protocol enforces a maximum of 5 concurrent active sessions per user.
|
|
1559
1774
|
*/
|
|
1560
1775
|
async getUserStats(user) {
|
|
1561
1776
|
const target = user || this.client.publicKey;
|
|
@@ -1575,7 +1790,8 @@ var GaslessClient = class {
|
|
|
1575
1790
|
totalSubsidized: new BN6(data.slice(48, 56), "le"),
|
|
1576
1791
|
totalVcoinFees: new BN6(data.slice(56, 64), "le"),
|
|
1577
1792
|
sessionsCreated: data.readUInt32LE(72),
|
|
1578
|
-
|
|
1793
|
+
activeSessions: data[76],
|
|
1794
|
+
activeSession: new PublicKey7(data.slice(77, 109))
|
|
1579
1795
|
};
|
|
1580
1796
|
} catch (error) {
|
|
1581
1797
|
console.warn("[ViWoSDK] gasless.getUserStats failed:", error instanceof Error ? error.message : error);
|
|
@@ -1712,6 +1928,9 @@ var GaslessClient = class {
|
|
|
1712
1928
|
// ============ Transaction Building ============
|
|
1713
1929
|
/**
|
|
1714
1930
|
* Build create session key transaction
|
|
1931
|
+
*
|
|
1932
|
+
* H-AUDIT-12: The protocol enforces a maximum of 5 concurrent active sessions per user.
|
|
1933
|
+
* Creating a session when the limit is reached will fail with MaxSessionsReached error.
|
|
1715
1934
|
*/
|
|
1716
1935
|
async buildCreateSessionTransaction(params) {
|
|
1717
1936
|
if (!this.client.publicKey) {
|
|
@@ -1723,6 +1942,10 @@ var GaslessClient = class {
|
|
|
1723
1942
|
if (!params.scope || params.scope === 0) {
|
|
1724
1943
|
throw new Error("At least one scope required");
|
|
1725
1944
|
}
|
|
1945
|
+
const stats = await this.getUserStats();
|
|
1946
|
+
if (stats && stats.activeSessions >= 5) {
|
|
1947
|
+
throw new Error("Maximum active sessions reached (5). Revoke an existing session first.");
|
|
1948
|
+
}
|
|
1726
1949
|
const duration = params.durationSeconds || GASLESS_CONSTANTS.sessionDuration;
|
|
1727
1950
|
const maxActions = params.maxActions || GASLESS_CONSTANTS.maxSessionActions;
|
|
1728
1951
|
const maxSpend = params.maxSpend || new BN6(GASLESS_CONSTANTS.maxSessionSpend * 1e9);
|
|
@@ -1833,6 +2056,23 @@ var IdentityClient = class {
|
|
|
1833
2056
|
return benefits[level] || [];
|
|
1834
2057
|
}
|
|
1835
2058
|
// ============ Transaction Building ============
|
|
2059
|
+
/**
|
|
2060
|
+
* Build subscribe transaction
|
|
2061
|
+
*
|
|
2062
|
+
* C-AUDIT-22: Non-free subscription tiers require actual USDC payment via SPL
|
|
2063
|
+
* transfer_checked. The transaction must include the user's USDC token account,
|
|
2064
|
+
* the USDC mint, and the treasury token account.
|
|
2065
|
+
*/
|
|
2066
|
+
async buildSubscribeTransaction(tier) {
|
|
2067
|
+
if (!this.client.publicKey) {
|
|
2068
|
+
throw new Error("Wallet not connected");
|
|
2069
|
+
}
|
|
2070
|
+
if (tier < 0 || tier > 4) {
|
|
2071
|
+
throw new Error("Invalid subscription tier (0-4)");
|
|
2072
|
+
}
|
|
2073
|
+
const tx = new Transaction7();
|
|
2074
|
+
return tx;
|
|
2075
|
+
}
|
|
1836
2076
|
/**
|
|
1837
2077
|
* Build create identity transaction
|
|
1838
2078
|
*/
|
|
@@ -1985,6 +2225,12 @@ var FiveAClient = class {
|
|
|
1985
2225
|
}
|
|
1986
2226
|
/**
|
|
1987
2227
|
* Check if user can vouch for another
|
|
2228
|
+
*
|
|
2229
|
+
* C-08: Mutual vouching is prevented — if the target has already vouched for you,
|
|
2230
|
+
* you cannot vouch for them. This is enforced on-chain via reverse_vouch_record check.
|
|
2231
|
+
*
|
|
2232
|
+
* M-18: Vouches expire after 1 year (MAX_VOUCH_AGE = 365 days). Expired vouches
|
|
2233
|
+
* cannot be evaluated and must be re-created.
|
|
1988
2234
|
*/
|
|
1989
2235
|
async canVouchFor(target) {
|
|
1990
2236
|
if (!this.client.publicKey) {
|
|
@@ -2027,6 +2273,12 @@ var FiveAClient = class {
|
|
|
2027
2273
|
// ============ Transaction Building ============
|
|
2028
2274
|
/**
|
|
2029
2275
|
* Build vouch transaction
|
|
2276
|
+
*
|
|
2277
|
+
* C-08: On-chain handler requires a reverse_vouch_record account to verify
|
|
2278
|
+
* mutual vouching is not occurring. The transaction must include this PDA.
|
|
2279
|
+
*
|
|
2280
|
+
* M-18: Vouches have a maximum age of 1 year. After that, evaluate_vouch
|
|
2281
|
+
* will reject with VouchExpired error.
|
|
2030
2282
|
*/
|
|
2031
2283
|
async buildVouchTransaction(target) {
|
|
2032
2284
|
if (!this.client.publicKey) {
|
|
@@ -2195,6 +2447,9 @@ var ContentClient = class {
|
|
|
2195
2447
|
}
|
|
2196
2448
|
/**
|
|
2197
2449
|
* Get content stats
|
|
2450
|
+
*
|
|
2451
|
+
* C-AUDIT-10: Engagement scores can only increase — the on-chain update_engagement
|
|
2452
|
+
* instruction enforces monotonic increase to prevent manipulation.
|
|
2198
2453
|
*/
|
|
2199
2454
|
async getContentStats(contentId) {
|
|
2200
2455
|
const content = await this.getContent(contentId);
|
|
@@ -2214,6 +2469,9 @@ var ContentClient = class {
|
|
|
2214
2469
|
// ============ Transaction Building ============
|
|
2215
2470
|
/**
|
|
2216
2471
|
* Build create content transaction
|
|
2472
|
+
*
|
|
2473
|
+
* C-AUDIT-11: Energy tiers are validated on-chain (valid range: 1-4).
|
|
2474
|
+
* Tier determines max energy and regen rate.
|
|
2217
2475
|
*/
|
|
2218
2476
|
async buildCreateContentTransaction(contentHash) {
|
|
2219
2477
|
if (!this.client.publicKey) {
|
package/package.json
CHANGED
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@viwoapp/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "ViWoApp SDK - TypeScript SDK for VCoin Protocol Integration",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"module": "dist/index.esm.js",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
|
-
"files": [
|
|
9
|
-
"dist"
|
|
10
|
-
],
|
|
11
|
-
"scripts": {
|
|
12
|
-
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
13
|
-
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
14
|
-
"lint": "eslint src --ext .ts",
|
|
15
|
-
"test": "jest",
|
|
16
|
-
"clean": "rm -rf dist"
|
|
17
|
-
},
|
|
18
|
-
"keywords": [
|
|
19
|
-
"viwoapp",
|
|
20
|
-
"vcoin",
|
|
21
|
-
"solana",
|
|
22
|
-
"blockchain",
|
|
23
|
-
"sdk"
|
|
24
|
-
],
|
|
25
|
-
"author": "ViWoApp Team",
|
|
26
|
-
"license": "MIT",
|
|
27
|
-
"dependencies": {
|
|
28
|
-
"@coral-xyz/anchor": "^0.32.0",
|
|
29
|
-
"@solana/web3.js": "^1.95.0",
|
|
30
|
-
"@solana/spl-token": "^0.4.0",
|
|
31
|
-
"bs58": "^5.0.0"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"@types/jest": "^29.5.0",
|
|
35
|
-
"@types/node": "^20.0.0",
|
|
36
|
-
"jest": "^29.7.0",
|
|
37
|
-
"ts-jest": "^29.1.0",
|
|
38
|
-
"tsup": "^8.0.0",
|
|
39
|
-
"typescript": "^5.0.0"
|
|
40
|
-
},
|
|
41
|
-
"peerDependencies": {
|
|
42
|
-
"@coral-xyz/anchor": ">=0.30.0",
|
|
43
|
-
"@solana/web3.js": ">=1.90.0"
|
|
44
|
-
},
|
|
45
|
-
"exports": {
|
|
46
|
-
".": {
|
|
47
|
-
"types": "./dist/index.d.ts",
|
|
48
|
-
"import": "./dist/index.esm.js",
|
|
49
|
-
"require": "./dist/index.js"
|
|
50
|
-
},
|
|
51
|
-
"./core": {
|
|
52
|
-
"types": "./dist/core/index.d.ts",
|
|
53
|
-
"import": "./dist/core/index.esm.js",
|
|
54
|
-
"require": "./dist/core/index.js"
|
|
55
|
-
},
|
|
56
|
-
"./staking": {
|
|
57
|
-
"types": "./dist/staking/index.d.ts",
|
|
58
|
-
"import": "./dist/staking/index.esm.js",
|
|
59
|
-
"require": "./dist/staking/index.js"
|
|
60
|
-
},
|
|
61
|
-
"./governance": {
|
|
62
|
-
"types": "./dist/governance/index.d.ts",
|
|
63
|
-
"import": "./dist/governance/index.esm.js",
|
|
64
|
-
"require": "./dist/governance/index.js"
|
|
65
|
-
},
|
|
66
|
-
"./rewards": {
|
|
67
|
-
"types": "./dist/rewards/index.d.ts",
|
|
68
|
-
"import": "./dist/rewards/index.esm.js",
|
|
69
|
-
"require": "./dist/rewards/index.js"
|
|
70
|
-
},
|
|
71
|
-
"./vilink": {
|
|
72
|
-
"types": "./dist/vilink/index.d.ts",
|
|
73
|
-
"import": "./dist/vilink/index.esm.js",
|
|
74
|
-
"require": "./dist/vilink/index.js"
|
|
75
|
-
},
|
|
76
|
-
"./gasless": {
|
|
77
|
-
"types": "./dist/gasless/index.d.ts",
|
|
78
|
-
"import": "./dist/gasless/index.esm.js",
|
|
79
|
-
"require": "./dist/gasless/index.js"
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@viwoapp/sdk",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "ViWoApp SDK - TypeScript SDK for VCoin Protocol Integration",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
13
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
14
|
+
"lint": "eslint src --ext .ts",
|
|
15
|
+
"test": "jest",
|
|
16
|
+
"clean": "rm -rf dist"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"viwoapp",
|
|
20
|
+
"vcoin",
|
|
21
|
+
"solana",
|
|
22
|
+
"blockchain",
|
|
23
|
+
"sdk"
|
|
24
|
+
],
|
|
25
|
+
"author": "ViWoApp Team",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@coral-xyz/anchor": "^0.32.0",
|
|
29
|
+
"@solana/web3.js": "^1.95.0",
|
|
30
|
+
"@solana/spl-token": "^0.4.0",
|
|
31
|
+
"bs58": "^5.0.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/jest": "^29.5.0",
|
|
35
|
+
"@types/node": "^20.0.0",
|
|
36
|
+
"jest": "^29.7.0",
|
|
37
|
+
"ts-jest": "^29.1.0",
|
|
38
|
+
"tsup": "^8.0.0",
|
|
39
|
+
"typescript": "^5.0.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@coral-xyz/anchor": ">=0.30.0",
|
|
43
|
+
"@solana/web3.js": ">=1.90.0"
|
|
44
|
+
},
|
|
45
|
+
"exports": {
|
|
46
|
+
".": {
|
|
47
|
+
"types": "./dist/index.d.ts",
|
|
48
|
+
"import": "./dist/index.esm.js",
|
|
49
|
+
"require": "./dist/index.js"
|
|
50
|
+
},
|
|
51
|
+
"./core": {
|
|
52
|
+
"types": "./dist/core/index.d.ts",
|
|
53
|
+
"import": "./dist/core/index.esm.js",
|
|
54
|
+
"require": "./dist/core/index.js"
|
|
55
|
+
},
|
|
56
|
+
"./staking": {
|
|
57
|
+
"types": "./dist/staking/index.d.ts",
|
|
58
|
+
"import": "./dist/staking/index.esm.js",
|
|
59
|
+
"require": "./dist/staking/index.js"
|
|
60
|
+
},
|
|
61
|
+
"./governance": {
|
|
62
|
+
"types": "./dist/governance/index.d.ts",
|
|
63
|
+
"import": "./dist/governance/index.esm.js",
|
|
64
|
+
"require": "./dist/governance/index.js"
|
|
65
|
+
},
|
|
66
|
+
"./rewards": {
|
|
67
|
+
"types": "./dist/rewards/index.d.ts",
|
|
68
|
+
"import": "./dist/rewards/index.esm.js",
|
|
69
|
+
"require": "./dist/rewards/index.js"
|
|
70
|
+
},
|
|
71
|
+
"./vilink": {
|
|
72
|
+
"types": "./dist/vilink/index.d.ts",
|
|
73
|
+
"import": "./dist/vilink/index.esm.js",
|
|
74
|
+
"require": "./dist/vilink/index.js"
|
|
75
|
+
},
|
|
76
|
+
"./gasless": {
|
|
77
|
+
"types": "./dist/gasless/index.d.ts",
|
|
78
|
+
"import": "./dist/gasless/index.esm.js",
|
|
79
|
+
"require": "./dist/gasless/index.js"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|