@viwoapp/sdk 0.1.3 → 0.1.6

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 CHANGED
@@ -5,9 +5,31 @@
5
5
 
6
6
  TypeScript SDK for VCoin Protocol Integration on Solana.
7
7
 
8
- **Version:** 0.1.3 (Phase 5 Security Update)
8
+ **Version:** 0.1.6 (Bug Fixes)
9
9
 
10
- ## What's New in v0.1.2
10
+ ## What's New in v0.1.5
11
+
12
+ - **ViLink Nonce-Based PDA:** Action PDAs now use deterministic `nonce` instead of `timestamp`
13
+ - **New Field:** `actionNonce` added to `ViLinkAction` interface
14
+ - **New Type:** `UserActionStatsExtended` with `actionNonce` counter
15
+ - **New Method:** `getViLinkActionByNonce()` PDA helper for new derivation
16
+ - **New Method:** `getNextNonce()` utility to get next nonce for action creation
17
+ - **Updated Methods:** `getAction()`, `isActionValid()`, `buildExecuteTipAction()` now use nonce
18
+ - **Deprecated:** `getActionByTimestamp()` - use `getAction()` with nonce instead
19
+
20
+ ### Breaking Change
21
+
22
+ ViLink action PDA derivation changed from timestamp to nonce:
23
+ ```typescript
24
+ // Old (deprecated)
25
+ const action = await client.vilink.getAction(creator, timestamp);
26
+
27
+ // New (v0.1.5+)
28
+ const nonce = await client.vilink.getNextNonce(creator);
29
+ const action = await client.vilink.getAction(creator, nonce);
30
+ ```
31
+
32
+ ## What's New in v0.1.4
11
33
 
12
34
  - **New Constants:** `MERKLE_PROOF_MAX_SIZE`, `MAX_EPOCH_BITMAP`, `LEGACY_SLASH_DEPRECATED`
13
35
  - **New Enum:** `VoteChoice` for typed governance voting (Against, For, Abstain)
@@ -155,8 +177,14 @@ const uri = client.vilink.generateUri(actionId);
155
177
  // Generate QR code data
156
178
  const qrData = client.vilink.generateQRData(actionId);
157
179
 
158
- // Check action validity
159
- const { valid, reason } = await client.vilink.isActionValid(creator, timestamp);
180
+ // Get next nonce for action creation (v0.1.5+)
181
+ const nonce = await client.vilink.getNextNonce();
182
+
183
+ // Get action by creator + nonce (v0.1.5+)
184
+ const action = await client.vilink.getAction(creator, nonce);
185
+
186
+ // Check action validity (uses nonce, not timestamp)
187
+ const { valid, reason } = await client.vilink.isActionValid(creator, nonce);
160
188
  ```
161
189
 
162
190
  ### Gasless (`client.gasless`)
@@ -255,7 +283,7 @@ import {
255
283
  SECURITY_CONSTANTS,
256
284
  VALID_URI_PREFIXES,
257
285
  MERKLE_CONSTANTS,
258
- // v0.1.2 additions
286
+ // v0.1.4 additions
259
287
  MERKLE_PROOF_MAX_SIZE, // 32 - prevents DoS
260
288
  MAX_EPOCH_BITMAP, // 1023 - max epoch with bitmap
261
289
  LEGACY_SLASH_DEPRECATED, // true - use propose_slash flow
@@ -267,9 +295,9 @@ SECURITY_CONSTANTS.slashApprovalTimelock; // 48 hours
267
295
  SECURITY_CONSTANTS.maxFeeSlippageBps; // 500 (5%)
268
296
  SECURITY_CONSTANTS.oracleConsensusRequired; // 3-of-N
269
297
  SECURITY_CONSTANTS.circuitBreakerCooldown; // 6 hours
270
- SECURITY_CONSTANTS.merkleProofMaxSize; // 32 (v0.1.2)
271
- SECURITY_CONSTANTS.maxEpochBitmap; // 1023 (v0.1.2)
272
- SECURITY_CONSTANTS.votingPowerVerifiedOnChain; // true (v0.1.2)
298
+ SECURITY_CONSTANTS.merkleProofMaxSize; // 32 (v0.1.4)
299
+ SECURITY_CONSTANTS.maxEpochBitmap; // 1023 (v0.1.4)
300
+ SECURITY_CONSTANTS.votingPowerVerifiedOnChain; // true (v0.1.4)
273
301
  ```
274
302
 
275
303
  ## Types
@@ -286,7 +314,7 @@ import type {
286
314
  Proposal,
287
315
  VoteRecord,
288
316
  ProposalStatus,
289
- VoteChoice, // v0.1.2: Against, For, Abstain
317
+ VoteChoice, // v0.1.4: Against, For, Abstain
290
318
  GovernanceConfig,
291
319
  Delegation,
292
320
  PrivateVotingConfig,
@@ -300,9 +328,10 @@ import type {
300
328
 
301
329
  // ViLink
302
330
  ViLinkConfig,
303
- ViLinkAction,
331
+ ViLinkAction, // v0.1.5: includes actionNonce
304
332
  ActionType,
305
333
  CreateActionParams,
334
+ UserActionStatsExtended, // v0.1.5: includes actionNonce counter
306
335
 
307
336
  // Gasless
308
337
  GaslessConfig,
package/dist/index.d.mts CHANGED
@@ -241,7 +241,19 @@ declare class PDAs {
241
241
  getEpochDistribution(epoch: BN): PublicKey;
242
242
  getUserClaim(user: PublicKey): PublicKey;
243
243
  getViLinkConfig(): PublicKey;
244
- getViLinkAction(creator: PublicKey, timestamp: BN): PublicKey;
244
+ /**
245
+ * Get ViLink action PDA
246
+ * @param creator - The action creator's public key
247
+ * @param nonce - M-04: The action nonce (deterministic counter, NOT timestamp)
248
+ * @deprecated Use getViLinkActionByNonce for clarity
249
+ */
250
+ getViLinkAction(creator: PublicKey, nonce: BN): PublicKey;
251
+ /**
252
+ * Get ViLink action PDA using nonce (M-04 fix)
253
+ * @param creator - The action creator's public key
254
+ * @param nonce - The action nonce from UserActionStats.actionNonce
255
+ */
256
+ getViLinkActionByNonce(creator: PublicKey, nonce: BN): PublicKey;
245
257
  getUserActionStats(user: PublicKey): PublicKey;
246
258
  getGaslessConfig(): PublicKey;
247
259
  getSessionKey(user: PublicKey, sessionPubkey: PublicKey): PublicKey;
@@ -442,6 +454,8 @@ interface ViLinkAction {
442
454
  executed: boolean;
443
455
  executionCount: number;
444
456
  maxExecutions: number;
457
+ /** M-04: Nonce used for deterministic PDA derivation (replaces timestamp) */
458
+ actionNonce: BN;
445
459
  }
446
460
  interface CreateActionParams {
447
461
  actionType: ActionType;
@@ -452,6 +466,27 @@ interface CreateActionParams {
452
466
  maxExecutions?: number;
453
467
  contentId?: Uint8Array;
454
468
  metadata?: string;
469
+ /**
470
+ * M-04: Nonce for deterministic PDA derivation.
471
+ * If not provided, fetched from user's action_nonce in UserActionStats.
472
+ */
473
+ nonce?: BN;
474
+ }
475
+ /** M-04: User action statistics with nonce tracking */
476
+ interface UserActionStatsExtended {
477
+ user: PublicKey;
478
+ actionsCreated: BN;
479
+ actionsExecuted: BN;
480
+ tipsSent: BN;
481
+ tipsReceived: BN;
482
+ vcoinSent: BN;
483
+ vcoinReceived: BN;
484
+ vouchesGiven: BN;
485
+ followsGiven: BN;
486
+ firstActionAt: BN;
487
+ lastActionAt: BN;
488
+ /** M-04: Next nonce to use when creating an action */
489
+ actionNonce: BN;
455
490
  }
456
491
  declare enum FeeMethod {
457
492
  PlatformSubsidized = 0,
@@ -824,9 +859,15 @@ declare class ViLinkClient {
824
859
  */
825
860
  getConfig(): Promise<ViLinkConfig | null>;
826
861
  /**
827
- * Get action by ID
862
+ * Get action by nonce (M-04: deterministic PDA derivation)
863
+ * @param creator - The action creator's public key
864
+ * @param nonce - The action nonce (from UserActionStats.actionNonce at creation time)
865
+ */
866
+ getAction(creator: PublicKey, nonce: BN): Promise<ViLinkAction | null>;
867
+ /**
868
+ * @deprecated Use getAction with nonce parameter instead
828
869
  */
829
- getAction(creator: PublicKey, timestamp: BN): Promise<ViLinkAction | null>;
870
+ getActionByTimestamp(creator: PublicKey, timestamp: BN): Promise<ViLinkAction | null>;
830
871
  /**
831
872
  * Get user action statistics
832
873
  */
@@ -841,8 +882,10 @@ declare class ViLinkClient {
841
882
  isActionTypeEnabled(actionType: ActionType): Promise<boolean>;
842
883
  /**
843
884
  * Check if action is valid for execution
885
+ * @param creator - The action creator's public key
886
+ * @param nonce - M-04: The action nonce (NOT timestamp)
844
887
  */
845
- isActionValid(creator: PublicKey, timestamp: BN): Promise<{
888
+ isActionValid(creator: PublicKey, nonce: BN): Promise<{
846
889
  valid: boolean;
847
890
  reason?: string;
848
891
  }>;
@@ -899,8 +942,15 @@ declare class ViLinkClient {
899
942
  }): Promise<Transaction>;
900
943
  /**
901
944
  * Build execute tip action transaction
945
+ * @param creator - The action creator's public key
946
+ * @param nonce - M-04: The action nonce (NOT timestamp)
947
+ */
948
+ buildExecuteTipAction(creator: PublicKey, nonce: BN): Promise<Transaction>;
949
+ /**
950
+ * Get the next nonce for creating an action (M-04)
951
+ * Fetches from UserActionStats.actionNonce on-chain
902
952
  */
903
- buildExecuteTipAction(creator: PublicKey, timestamp: BN): Promise<Transaction>;
953
+ getNextNonce(user?: PublicKey): Promise<BN>;
904
954
  }
905
955
 
906
956
  /**
@@ -1352,4 +1402,4 @@ declare class StakingClient {
1352
1402
  buildExtendLockTransaction(newDuration: number): Promise<Transaction>;
1353
1403
  }
1354
1404
 
1355
- export { ACTION_SCOPES, ActionType, CONTENT_CONSTANTS, type ClaimRewardsParams, type ConnectionConfig, ContentClient, type ContentRecord, ContentState, type CreateActionParams, type CreateProposalParams, type CreateSessionParams, type DecryptionShare, type Delegation, type EpochDistribution, FIVE_A_CONSTANTS, FeeMethod, FiveAClient, type FiveAConfig, type FiveAScore, GASLESS_CONSTANTS, GOVERNANCE_CONSTANTS, GaslessClient, type GaslessConfig, GovernanceClient, type GovernanceConfig, type HookConfig, type Identity, IdentityClient, type IdentityConfig, LEGACY_SLASH_DEPRECATED, LOCK_DURATIONS, MAX_EPOCH_BITMAP, MAX_URI_LENGTH, MERKLE_CONSTANTS, MERKLE_PROOF_MAX_SIZE, PDAs, PROGRAM_IDS, type PendingAuthorityFields, type PendingScoreUpdate, type PrivateVotingConfig, type Proposal, ProposalStatus, type RegistryConfig, RewardsClient, type RewardsPoolConfig, SECURITY_CONSTANTS, SEEDS, SSCRE_CONSTANTS, STAKING_TIERS, type SessionKey, type SlashRequest, SlashStatus, type StakeParams, StakingClient, type StakingPool, StakingTier, TransactionBuilder, type UserClaim, type UserEnergy, type UserGaslessStats, type UserStake, VALID_URI_PREFIXES, VCOIN_DECIMALS, VCOIN_INITIAL_CIRCULATING, VCOIN_TOTAL_SUPPLY, type VCoinConfig, VEVCOIN_DECIMALS, VILINK_CONSTANTS, VerificationLevel, type ViLinkAction, ViLinkClient, type ViLinkConfig, ViWoClient, ViWoConnection, VoteChoice, type VoteRecord, type VouchRecord, type WalletAdapter, dateToTimestamp, formatVCoin, getCurrentTimestamp, parseVCoin, timestampToDate };
1405
+ export { ACTION_SCOPES, ActionType, CONTENT_CONSTANTS, type ClaimRewardsParams, type ConnectionConfig, ContentClient, type ContentRecord, ContentState, type CreateActionParams, type CreateProposalParams, type CreateSessionParams, type DecryptionShare, type Delegation, type EpochDistribution, FIVE_A_CONSTANTS, FeeMethod, FiveAClient, type FiveAConfig, type FiveAScore, GASLESS_CONSTANTS, GOVERNANCE_CONSTANTS, GaslessClient, type GaslessConfig, GovernanceClient, type GovernanceConfig, type HookConfig, type Identity, IdentityClient, type IdentityConfig, LEGACY_SLASH_DEPRECATED, LOCK_DURATIONS, MAX_EPOCH_BITMAP, MAX_URI_LENGTH, MERKLE_CONSTANTS, MERKLE_PROOF_MAX_SIZE, PDAs, PROGRAM_IDS, type PendingAuthorityFields, type PendingScoreUpdate, type PrivateVotingConfig, type Proposal, ProposalStatus, type RegistryConfig, RewardsClient, type RewardsPoolConfig, SECURITY_CONSTANTS, SEEDS, SSCRE_CONSTANTS, STAKING_TIERS, type SessionKey, type SlashRequest, SlashStatus, type StakeParams, StakingClient, type StakingPool, StakingTier, TransactionBuilder, type UserActionStatsExtended, type UserClaim, type UserEnergy, type UserGaslessStats, type UserStake, VALID_URI_PREFIXES, VCOIN_DECIMALS, VCOIN_INITIAL_CIRCULATING, VCOIN_TOTAL_SUPPLY, type VCoinConfig, VEVCOIN_DECIMALS, VILINK_CONSTANTS, VerificationLevel, type ViLinkAction, ViLinkClient, type ViLinkConfig, ViWoClient, ViWoConnection, VoteChoice, type VoteRecord, type VouchRecord, type WalletAdapter, dateToTimestamp, formatVCoin, getCurrentTimestamp, parseVCoin, timestampToDate };
package/dist/index.d.ts CHANGED
@@ -241,7 +241,19 @@ declare class PDAs {
241
241
  getEpochDistribution(epoch: BN): PublicKey;
242
242
  getUserClaim(user: PublicKey): PublicKey;
243
243
  getViLinkConfig(): PublicKey;
244
- getViLinkAction(creator: PublicKey, timestamp: BN): PublicKey;
244
+ /**
245
+ * Get ViLink action PDA
246
+ * @param creator - The action creator's public key
247
+ * @param nonce - M-04: The action nonce (deterministic counter, NOT timestamp)
248
+ * @deprecated Use getViLinkActionByNonce for clarity
249
+ */
250
+ getViLinkAction(creator: PublicKey, nonce: BN): PublicKey;
251
+ /**
252
+ * Get ViLink action PDA using nonce (M-04 fix)
253
+ * @param creator - The action creator's public key
254
+ * @param nonce - The action nonce from UserActionStats.actionNonce
255
+ */
256
+ getViLinkActionByNonce(creator: PublicKey, nonce: BN): PublicKey;
245
257
  getUserActionStats(user: PublicKey): PublicKey;
246
258
  getGaslessConfig(): PublicKey;
247
259
  getSessionKey(user: PublicKey, sessionPubkey: PublicKey): PublicKey;
@@ -442,6 +454,8 @@ interface ViLinkAction {
442
454
  executed: boolean;
443
455
  executionCount: number;
444
456
  maxExecutions: number;
457
+ /** M-04: Nonce used for deterministic PDA derivation (replaces timestamp) */
458
+ actionNonce: BN;
445
459
  }
446
460
  interface CreateActionParams {
447
461
  actionType: ActionType;
@@ -452,6 +466,27 @@ interface CreateActionParams {
452
466
  maxExecutions?: number;
453
467
  contentId?: Uint8Array;
454
468
  metadata?: string;
469
+ /**
470
+ * M-04: Nonce for deterministic PDA derivation.
471
+ * If not provided, fetched from user's action_nonce in UserActionStats.
472
+ */
473
+ nonce?: BN;
474
+ }
475
+ /** M-04: User action statistics with nonce tracking */
476
+ interface UserActionStatsExtended {
477
+ user: PublicKey;
478
+ actionsCreated: BN;
479
+ actionsExecuted: BN;
480
+ tipsSent: BN;
481
+ tipsReceived: BN;
482
+ vcoinSent: BN;
483
+ vcoinReceived: BN;
484
+ vouchesGiven: BN;
485
+ followsGiven: BN;
486
+ firstActionAt: BN;
487
+ lastActionAt: BN;
488
+ /** M-04: Next nonce to use when creating an action */
489
+ actionNonce: BN;
455
490
  }
456
491
  declare enum FeeMethod {
457
492
  PlatformSubsidized = 0,
@@ -824,9 +859,15 @@ declare class ViLinkClient {
824
859
  */
825
860
  getConfig(): Promise<ViLinkConfig | null>;
826
861
  /**
827
- * Get action by ID
862
+ * Get action by nonce (M-04: deterministic PDA derivation)
863
+ * @param creator - The action creator's public key
864
+ * @param nonce - The action nonce (from UserActionStats.actionNonce at creation time)
865
+ */
866
+ getAction(creator: PublicKey, nonce: BN): Promise<ViLinkAction | null>;
867
+ /**
868
+ * @deprecated Use getAction with nonce parameter instead
828
869
  */
829
- getAction(creator: PublicKey, timestamp: BN): Promise<ViLinkAction | null>;
870
+ getActionByTimestamp(creator: PublicKey, timestamp: BN): Promise<ViLinkAction | null>;
830
871
  /**
831
872
  * Get user action statistics
832
873
  */
@@ -841,8 +882,10 @@ declare class ViLinkClient {
841
882
  isActionTypeEnabled(actionType: ActionType): Promise<boolean>;
842
883
  /**
843
884
  * Check if action is valid for execution
885
+ * @param creator - The action creator's public key
886
+ * @param nonce - M-04: The action nonce (NOT timestamp)
844
887
  */
845
- isActionValid(creator: PublicKey, timestamp: BN): Promise<{
888
+ isActionValid(creator: PublicKey, nonce: BN): Promise<{
846
889
  valid: boolean;
847
890
  reason?: string;
848
891
  }>;
@@ -899,8 +942,15 @@ declare class ViLinkClient {
899
942
  }): Promise<Transaction>;
900
943
  /**
901
944
  * Build execute tip action transaction
945
+ * @param creator - The action creator's public key
946
+ * @param nonce - M-04: The action nonce (NOT timestamp)
947
+ */
948
+ buildExecuteTipAction(creator: PublicKey, nonce: BN): Promise<Transaction>;
949
+ /**
950
+ * Get the next nonce for creating an action (M-04)
951
+ * Fetches from UserActionStats.actionNonce on-chain
902
952
  */
903
- buildExecuteTipAction(creator: PublicKey, timestamp: BN): Promise<Transaction>;
953
+ getNextNonce(user?: PublicKey): Promise<BN>;
904
954
  }
905
955
 
906
956
  /**
@@ -1352,4 +1402,4 @@ declare class StakingClient {
1352
1402
  buildExtendLockTransaction(newDuration: number): Promise<Transaction>;
1353
1403
  }
1354
1404
 
1355
- export { ACTION_SCOPES, ActionType, CONTENT_CONSTANTS, type ClaimRewardsParams, type ConnectionConfig, ContentClient, type ContentRecord, ContentState, type CreateActionParams, type CreateProposalParams, type CreateSessionParams, type DecryptionShare, type Delegation, type EpochDistribution, FIVE_A_CONSTANTS, FeeMethod, FiveAClient, type FiveAConfig, type FiveAScore, GASLESS_CONSTANTS, GOVERNANCE_CONSTANTS, GaslessClient, type GaslessConfig, GovernanceClient, type GovernanceConfig, type HookConfig, type Identity, IdentityClient, type IdentityConfig, LEGACY_SLASH_DEPRECATED, LOCK_DURATIONS, MAX_EPOCH_BITMAP, MAX_URI_LENGTH, MERKLE_CONSTANTS, MERKLE_PROOF_MAX_SIZE, PDAs, PROGRAM_IDS, type PendingAuthorityFields, type PendingScoreUpdate, type PrivateVotingConfig, type Proposal, ProposalStatus, type RegistryConfig, RewardsClient, type RewardsPoolConfig, SECURITY_CONSTANTS, SEEDS, SSCRE_CONSTANTS, STAKING_TIERS, type SessionKey, type SlashRequest, SlashStatus, type StakeParams, StakingClient, type StakingPool, StakingTier, TransactionBuilder, type UserClaim, type UserEnergy, type UserGaslessStats, type UserStake, VALID_URI_PREFIXES, VCOIN_DECIMALS, VCOIN_INITIAL_CIRCULATING, VCOIN_TOTAL_SUPPLY, type VCoinConfig, VEVCOIN_DECIMALS, VILINK_CONSTANTS, VerificationLevel, type ViLinkAction, ViLinkClient, type ViLinkConfig, ViWoClient, ViWoConnection, VoteChoice, type VoteRecord, type VouchRecord, type WalletAdapter, dateToTimestamp, formatVCoin, getCurrentTimestamp, parseVCoin, timestampToDate };
1405
+ export { ACTION_SCOPES, ActionType, CONTENT_CONSTANTS, type ClaimRewardsParams, type ConnectionConfig, ContentClient, type ContentRecord, ContentState, type CreateActionParams, type CreateProposalParams, type CreateSessionParams, type DecryptionShare, type Delegation, type EpochDistribution, FIVE_A_CONSTANTS, FeeMethod, FiveAClient, type FiveAConfig, type FiveAScore, GASLESS_CONSTANTS, GOVERNANCE_CONSTANTS, GaslessClient, type GaslessConfig, GovernanceClient, type GovernanceConfig, type HookConfig, type Identity, IdentityClient, type IdentityConfig, LEGACY_SLASH_DEPRECATED, LOCK_DURATIONS, MAX_EPOCH_BITMAP, MAX_URI_LENGTH, MERKLE_CONSTANTS, MERKLE_PROOF_MAX_SIZE, PDAs, PROGRAM_IDS, type PendingAuthorityFields, type PendingScoreUpdate, type PrivateVotingConfig, type Proposal, ProposalStatus, type RegistryConfig, RewardsClient, type RewardsPoolConfig, SECURITY_CONSTANTS, SEEDS, SSCRE_CONSTANTS, STAKING_TIERS, type SessionKey, type SlashRequest, SlashStatus, type StakeParams, StakingClient, type StakingPool, StakingTier, TransactionBuilder, type UserActionStatsExtended, type UserClaim, type UserEnergy, type UserGaslessStats, type UserStake, VALID_URI_PREFIXES, VCOIN_DECIMALS, VCOIN_INITIAL_CIRCULATING, VCOIN_TOTAL_SUPPLY, type VCoinConfig, VEVCOIN_DECIMALS, VILINK_CONSTANTS, VerificationLevel, type ViLinkAction, ViLinkClient, type ViLinkConfig, ViWoClient, ViWoConnection, VoteChoice, type VoteRecord, type VouchRecord, type WalletAdapter, dateToTimestamp, formatVCoin, getCurrentTimestamp, parseVCoin, timestampToDate };
package/dist/index.js CHANGED
@@ -428,12 +428,26 @@ var PDAs = class {
428
428
  );
429
429
  return pda;
430
430
  }
431
- getViLinkAction(creator, timestamp) {
431
+ /**
432
+ * Get ViLink action PDA
433
+ * @param creator - The action creator's public key
434
+ * @param nonce - M-04: The action nonce (deterministic counter, NOT timestamp)
435
+ * @deprecated Use getViLinkActionByNonce for clarity
436
+ */
437
+ getViLinkAction(creator, nonce) {
438
+ return this.getViLinkActionByNonce(creator, nonce);
439
+ }
440
+ /**
441
+ * Get ViLink action PDA using nonce (M-04 fix)
442
+ * @param creator - The action creator's public key
443
+ * @param nonce - The action nonce from UserActionStats.actionNonce
444
+ */
445
+ getViLinkActionByNonce(creator, nonce) {
432
446
  const [pda] = import_web32.PublicKey.findProgramAddressSync(
433
447
  [
434
448
  Buffer.from(SEEDS.action),
435
449
  creator.toBuffer(),
436
- timestamp.toArrayLike(Buffer, "le", 8)
450
+ nonce.toArrayLike(Buffer, "le", 8)
437
451
  ],
438
452
  this.programIds.vilinkProtocol
439
453
  );
@@ -1291,11 +1305,13 @@ var ViLinkClient = class {
1291
1305
  }
1292
1306
  }
1293
1307
  /**
1294
- * Get action by ID
1308
+ * Get action by nonce (M-04: deterministic PDA derivation)
1309
+ * @param creator - The action creator's public key
1310
+ * @param nonce - The action nonce (from UserActionStats.actionNonce at creation time)
1295
1311
  */
1296
- async getAction(creator, timestamp) {
1312
+ async getAction(creator, nonce) {
1297
1313
  try {
1298
- const actionPda = this.client.pdas.getViLinkAction(creator, timestamp);
1314
+ const actionPda = this.client.pdas.getViLinkActionByNonce(creator, nonce);
1299
1315
  const accountInfo = await this.client.connection.connection.getAccountInfo(actionPda);
1300
1316
  if (!accountInfo) {
1301
1317
  return null;
@@ -1310,12 +1326,20 @@ var ViLinkClient = class {
1310
1326
  expiresAt: new import_anchor5.BN(data.slice(145, 153), "le"),
1311
1327
  executed: data[153] !== 0,
1312
1328
  executionCount: data.readUInt32LE(193),
1313
- maxExecutions: data.readUInt32LE(197)
1329
+ maxExecutions: data.readUInt32LE(197),
1330
+ actionNonce: nonce
1331
+ // M-04: Store nonce for reference
1314
1332
  };
1315
1333
  } catch {
1316
1334
  return null;
1317
1335
  }
1318
1336
  }
1337
+ /**
1338
+ * @deprecated Use getAction with nonce parameter instead
1339
+ */
1340
+ async getActionByTimestamp(creator, timestamp) {
1341
+ return this.getAction(creator, timestamp);
1342
+ }
1319
1343
  /**
1320
1344
  * Get user action statistics
1321
1345
  */
@@ -1370,9 +1394,11 @@ var ViLinkClient = class {
1370
1394
  }
1371
1395
  /**
1372
1396
  * Check if action is valid for execution
1397
+ * @param creator - The action creator's public key
1398
+ * @param nonce - M-04: The action nonce (NOT timestamp)
1373
1399
  */
1374
- async isActionValid(creator, timestamp) {
1375
- const action = await this.getAction(creator, timestamp);
1400
+ async isActionValid(creator, nonce) {
1401
+ const action = await this.getAction(creator, nonce);
1376
1402
  if (!action) {
1377
1403
  return { valid: false, reason: "Action not found" };
1378
1404
  }
@@ -1472,22 +1498,35 @@ var ViLinkClient = class {
1472
1498
  }
1473
1499
  /**
1474
1500
  * Build execute tip action transaction
1501
+ * @param creator - The action creator's public key
1502
+ * @param nonce - M-04: The action nonce (NOT timestamp)
1475
1503
  */
1476
- async buildExecuteTipAction(creator, timestamp) {
1504
+ async buildExecuteTipAction(creator, nonce) {
1477
1505
  if (!this.client.publicKey) {
1478
1506
  throw new Error("Wallet not connected");
1479
1507
  }
1480
- const { valid, reason } = await this.isActionValid(creator, timestamp);
1508
+ const { valid, reason } = await this.isActionValid(creator, nonce);
1481
1509
  if (!valid) {
1482
1510
  throw new Error(reason);
1483
1511
  }
1484
- const action = await this.getAction(creator, timestamp);
1512
+ const action = await this.getAction(creator, nonce);
1485
1513
  if (action?.creator.equals(this.client.publicKey)) {
1486
1514
  throw new Error("Cannot execute own action");
1487
1515
  }
1488
1516
  const tx = new import_web36.Transaction();
1489
1517
  return tx;
1490
1518
  }
1519
+ /**
1520
+ * Get the next nonce for creating an action (M-04)
1521
+ * Fetches from UserActionStats.actionNonce on-chain
1522
+ */
1523
+ async getNextNonce(user) {
1524
+ const stats = await this.getUserStats(user);
1525
+ if (!stats) {
1526
+ return new import_anchor5.BN(0);
1527
+ }
1528
+ return new import_anchor5.BN(stats.actionsCreated.toNumber());
1529
+ }
1491
1530
  };
1492
1531
 
1493
1532
  // src/gasless/index.ts
package/dist/index.mjs CHANGED
@@ -359,12 +359,26 @@ var PDAs = class {
359
359
  );
360
360
  return pda;
361
361
  }
362
- getViLinkAction(creator, timestamp) {
362
+ /**
363
+ * Get ViLink action PDA
364
+ * @param creator - The action creator's public key
365
+ * @param nonce - M-04: The action nonce (deterministic counter, NOT timestamp)
366
+ * @deprecated Use getViLinkActionByNonce for clarity
367
+ */
368
+ getViLinkAction(creator, nonce) {
369
+ return this.getViLinkActionByNonce(creator, nonce);
370
+ }
371
+ /**
372
+ * Get ViLink action PDA using nonce (M-04 fix)
373
+ * @param creator - The action creator's public key
374
+ * @param nonce - The action nonce from UserActionStats.actionNonce
375
+ */
376
+ getViLinkActionByNonce(creator, nonce) {
363
377
  const [pda] = PublicKey2.findProgramAddressSync(
364
378
  [
365
379
  Buffer.from(SEEDS.action),
366
380
  creator.toBuffer(),
367
- timestamp.toArrayLike(Buffer, "le", 8)
381
+ nonce.toArrayLike(Buffer, "le", 8)
368
382
  ],
369
383
  this.programIds.vilinkProtocol
370
384
  );
@@ -1222,11 +1236,13 @@ var ViLinkClient = class {
1222
1236
  }
1223
1237
  }
1224
1238
  /**
1225
- * Get action by ID
1239
+ * Get action by nonce (M-04: deterministic PDA derivation)
1240
+ * @param creator - The action creator's public key
1241
+ * @param nonce - The action nonce (from UserActionStats.actionNonce at creation time)
1226
1242
  */
1227
- async getAction(creator, timestamp) {
1243
+ async getAction(creator, nonce) {
1228
1244
  try {
1229
- const actionPda = this.client.pdas.getViLinkAction(creator, timestamp);
1245
+ const actionPda = this.client.pdas.getViLinkActionByNonce(creator, nonce);
1230
1246
  const accountInfo = await this.client.connection.connection.getAccountInfo(actionPda);
1231
1247
  if (!accountInfo) {
1232
1248
  return null;
@@ -1241,12 +1257,20 @@ var ViLinkClient = class {
1241
1257
  expiresAt: new BN5(data.slice(145, 153), "le"),
1242
1258
  executed: data[153] !== 0,
1243
1259
  executionCount: data.readUInt32LE(193),
1244
- maxExecutions: data.readUInt32LE(197)
1260
+ maxExecutions: data.readUInt32LE(197),
1261
+ actionNonce: nonce
1262
+ // M-04: Store nonce for reference
1245
1263
  };
1246
1264
  } catch {
1247
1265
  return null;
1248
1266
  }
1249
1267
  }
1268
+ /**
1269
+ * @deprecated Use getAction with nonce parameter instead
1270
+ */
1271
+ async getActionByTimestamp(creator, timestamp) {
1272
+ return this.getAction(creator, timestamp);
1273
+ }
1250
1274
  /**
1251
1275
  * Get user action statistics
1252
1276
  */
@@ -1301,9 +1325,11 @@ var ViLinkClient = class {
1301
1325
  }
1302
1326
  /**
1303
1327
  * Check if action is valid for execution
1328
+ * @param creator - The action creator's public key
1329
+ * @param nonce - M-04: The action nonce (NOT timestamp)
1304
1330
  */
1305
- async isActionValid(creator, timestamp) {
1306
- const action = await this.getAction(creator, timestamp);
1331
+ async isActionValid(creator, nonce) {
1332
+ const action = await this.getAction(creator, nonce);
1307
1333
  if (!action) {
1308
1334
  return { valid: false, reason: "Action not found" };
1309
1335
  }
@@ -1403,22 +1429,35 @@ var ViLinkClient = class {
1403
1429
  }
1404
1430
  /**
1405
1431
  * Build execute tip action transaction
1432
+ * @param creator - The action creator's public key
1433
+ * @param nonce - M-04: The action nonce (NOT timestamp)
1406
1434
  */
1407
- async buildExecuteTipAction(creator, timestamp) {
1435
+ async buildExecuteTipAction(creator, nonce) {
1408
1436
  if (!this.client.publicKey) {
1409
1437
  throw new Error("Wallet not connected");
1410
1438
  }
1411
- const { valid, reason } = await this.isActionValid(creator, timestamp);
1439
+ const { valid, reason } = await this.isActionValid(creator, nonce);
1412
1440
  if (!valid) {
1413
1441
  throw new Error(reason);
1414
1442
  }
1415
- const action = await this.getAction(creator, timestamp);
1443
+ const action = await this.getAction(creator, nonce);
1416
1444
  if (action?.creator.equals(this.client.publicKey)) {
1417
1445
  throw new Error("Cannot execute own action");
1418
1446
  }
1419
1447
  const tx = new Transaction5();
1420
1448
  return tx;
1421
1449
  }
1450
+ /**
1451
+ * Get the next nonce for creating an action (M-04)
1452
+ * Fetches from UserActionStats.actionNonce on-chain
1453
+ */
1454
+ async getNextNonce(user) {
1455
+ const stats = await this.getUserStats(user);
1456
+ if (!stats) {
1457
+ return new BN5(0);
1458
+ }
1459
+ return new BN5(stats.actionsCreated.toNumber());
1460
+ }
1422
1461
  };
1423
1462
 
1424
1463
  // src/gasless/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viwoapp/sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
4
4
  "description": "ViWoApp SDK - TypeScript SDK for VCoin Protocol Integration",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",