solotto 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,6 +24,7 @@ A JavaScript SDK for interacting with the Solotto on-chain lottery program on So
24
24
  - [ClaimTicket](#claimticket)
25
25
  - [Boost](#boost)
26
26
  - [GetBoosters](#getboosters)
27
+ - [GetMessages](#getmessages)
27
28
  - [GetLottery](#getlottery)
28
29
  - [GetLotteries](#getlotteries)
29
30
  - [GetTicket](#getticket)
@@ -341,6 +342,7 @@ const grouped = await lottery.GetBoosters(authority, lotteryId, true);
341
342
  authority: "Pubkey...", // Lottery authority public key
342
343
  amount: 0.5, // Boost amount in SOL
343
344
  message: "Good luck!", // Optional memo message (empty string if none)
345
+ time: 1700000000, // Unix block timestamp of the boost transaction
344
346
  signature: "TxSignature...",
345
347
  },
346
348
  // ...
@@ -353,7 +355,7 @@ const grouped = await lottery.GetBoosters(authority, lotteryId, true);
353
355
  {
354
356
  "BoosterPubkey...": {
355
357
  boost: [
356
- { booster: "Pubkey...", lotteryId: 1, authority: "Pubkey...", amount: 0.5, message: "...", signature: "TxSig..." },
358
+ { booster: "Pubkey...", lotteryId: 1, authority: "Pubkey...", amount: 0.5, message: "...", time: 1700000000, signature: "TxSig..." },
357
359
  // ...
358
360
  ],
359
361
  total: 1.5, // Sum of all boost amounts in SOL
@@ -365,6 +367,41 @@ const grouped = await lottery.GetBoosters(authority, lotteryId, true);
365
367
 
366
368
  ---
367
369
 
370
+ #### GetMessages
371
+
372
+ Retrieves boost memo messages from on-chain transaction history. Paginates through program signatures and extracts messages from transactions tagged with `:booster:`. Useful for displaying a feed of booster shoutouts.
373
+
374
+ ```js
375
+ // Get the latest boost messages (up to 1000)
376
+ const messages = await lottery.GetMessages();
377
+
378
+ // Get up to 200 messages
379
+ const recent = await lottery.GetMessages(200);
380
+
381
+ // Paginate: get messages until a specific signature
382
+ const older = await lottery.GetMessages(1000, "LastKnownSignature...");
383
+ ```
384
+
385
+ | Parameter | Type | Default | Description |
386
+ |---|---|---|---|
387
+ | `limit` | `Number` | `1000` | Maximum number of transactions to scan. Paginates automatically if needed. |
388
+ | `until` | `String \| null` | `null` | Stop scanning at this transaction signature (exclusive). Useful for pagination. |
389
+
390
+ **Returns:** An array of message objects:
391
+
392
+ ```js
393
+ [
394
+ {
395
+ message: "Good luck everyone!", // The booster's memo text
396
+ time: 1700000000, // Unix block timestamp
397
+ signature: "TxSignature...", // Transaction signature
398
+ },
399
+ // ...
400
+ ]
401
+ ```
402
+
403
+ ---
404
+
368
405
  #### GetLottery
369
406
 
370
407
  Fetches the full on-chain state of a lottery.
@@ -457,7 +494,7 @@ const ticket = await lottery.GetTicket(authority, lotteryId, ticketNumber);
457
494
 
458
495
  #### GetTickets
459
496
 
460
- Fetches all tickets for a lottery, optionally filtered by buyer and/or grouped by owner.
497
+ Fetches all tickets for a lottery, optionally filtered by buyer, grouped by owner, and/or enriched with purchase timestamps.
461
498
 
462
499
  ```js
463
500
  // Get all tickets
@@ -468,6 +505,9 @@ const myTickets = await lottery.GetTickets(authority, lotteryId, buyer);
468
505
 
469
506
  // Get all tickets grouped by owner
470
507
  const grouped = await lottery.GetTickets(authority, lotteryId, false, true);
508
+
509
+ // Get all tickets with purchase timestamps
510
+ const withTime = await lottery.GetTickets(authority, lotteryId, false, false, true);
471
511
  ```
472
512
 
473
513
  | Parameter | Type | Default | Description |
@@ -476,6 +516,7 @@ const grouped = await lottery.GetTickets(authority, lotteryId, false, true);
476
516
  | `lotteryId` | `Number` | — | The lottery ID. |
477
517
  | `buyer` | `{publicKey} \| false` | `false` | Optional buyer to filter by. |
478
518
  | `group` | `Boolean` | `false` | If `true`, groups tickets by owner. |
519
+ | `time` | `Boolean` | `false` | If `true`, fetches the block timestamp for each ticket (slower — requires extra RPC calls). |
479
520
 
480
521
  **Returns (ungrouped):**
481
522
 
@@ -492,6 +533,7 @@ const grouped = await lottery.GetTickets(authority, lotteryId, false, true);
492
533
  ticketReceipt: "Pubkey...",
493
534
  ticketNumber: 42,
494
535
  ticketPda: "Pubkey...",
536
+ time: null, // Unix timestamp when time=true, null otherwise
495
537
  },
496
538
  // ... sorted descending by ticket number
497
539
  ],
@@ -511,7 +553,7 @@ const grouped = await lottery.GetTickets(authority, lotteryId, false, true);
511
553
  owner: "Pubkey...",
512
554
  ticketCount: 3,
513
555
  tickets: [
514
- { owner: "Pubkey...", lottery: "Pubkey...", ticketReceipt: "Pubkey...", ticketNumber: 42, ticketPda: "Pubkey..." },
556
+ { owner: "Pubkey...", lottery: "Pubkey...", ticketReceipt: "Pubkey...", ticketNumber: 42, ticketPda: "Pubkey...", time: null },
515
557
  // ...
516
558
  ],
517
559
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solotto",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Solana lottery client",
5
5
  "type": "module",
6
6
  "types": "./solotto.d.ts",
package/solotto.d.ts CHANGED
@@ -105,6 +105,8 @@ declare module "solotto" {
105
105
  ticketReceipt: string;
106
106
  ticketNumber: number;
107
107
  ticketPda: string;
108
+ /** Unix block timestamp of ticket purchase, or `null` when `time=false`. */
109
+ time: number | null;
108
110
  }
109
111
 
110
112
  interface GroupedTicketOwner {
@@ -160,6 +162,8 @@ declare module "solotto" {
160
162
  amount: number;
161
163
  /** Optional memo message from the booster. */
162
164
  message: string;
165
+ /** Unix block timestamp of the boost transaction. */
166
+ time: number;
163
167
  /** Transaction signature. */
164
168
  signature: string;
165
169
  }
@@ -177,6 +181,15 @@ declare module "solotto" {
177
181
  [boosterAddress: string]: GroupedBooster;
178
182
  }
179
183
 
184
+ interface MessageRecord {
185
+ /** The booster's memo text. */
186
+ message: string;
187
+ /** Unix block timestamp of the transaction. */
188
+ time: number;
189
+ /** Transaction signature. */
190
+ signature: string;
191
+ }
192
+
180
193
  // ── Authority-like objects ────────────────────────────────────────────
181
194
 
182
195
  /** An object with at least a `publicKey` property (e.g. a Keypair without the secret key). */
@@ -310,12 +323,13 @@ declare module "solotto" {
310
323
  ticket: number
311
324
  ): Promise<TicketInfo>;
312
325
 
313
- /** Fetch all tickets for a lottery, optionally filtered by buyer and/or grouped by owner. */
326
+ /** Fetch all tickets for a lottery, optionally filtered by buyer, grouped by owner, and/or with timestamps. */
314
327
  GetTickets(
315
328
  authority: HasPublicKey,
316
329
  lotteryId: number,
317
330
  buyer?: HasPublicKey | false,
318
- group?: boolean
331
+ group?: boolean,
332
+ time?: boolean
319
333
  ): Promise<TicketListResult>;
320
334
 
321
335
  /**
@@ -362,6 +376,16 @@ declare module "solotto" {
362
376
  limit?: number
363
377
  ): Promise<BoosterRecord[] | GroupedBoostersResult>;
364
378
 
379
+ /**
380
+ * Retrieve boost memo messages from on-chain transaction history.
381
+ * @param limit - Maximum number of transactions to scan (paginates automatically).
382
+ * @param until - Stop scanning at this transaction signature (exclusive).
383
+ */
384
+ GetMessages(
385
+ limit?: number,
386
+ until?: string | null
387
+ ): Promise<MessageRecord[]>;
388
+
365
389
  /** Derive the lottery PDA. */
366
390
  DeriveLotteryPDA(
367
391
  authority: PublicKey,
package/solotto.js CHANGED
@@ -441,7 +441,7 @@ class Lottery extends EventEmitter {
441
441
  * @param {Number} lotteryId - Lottery Id
442
442
  * @param {PublicKey} buyer - Ticket Buyer Optional
443
443
  */
444
- async GetTickets(authority, lotteryId, buyer = false, group = false) {
444
+ async GetTickets(authority, lotteryId, buyer = false, group = false, time = false) {
445
445
  const [lotteryPDA] = await this.DeriveLotteryPDA(authority.publicKey, lotteryId);
446
446
  const filters = [];
447
447
  filters.push({dataSize: 104});
@@ -459,6 +459,11 @@ class Lottery extends EventEmitter {
459
459
  newTicket.ticketReceipt = new PublicKey(decoded.ticketReceipt).toString();
460
460
  newTicket.ticketNumber = parseInt(new BN(decoded.ticketNumber, 10, "le"));
461
461
  newTicket.ticketPda = data.pubkey.toString();
462
+ newTicket.time = null;
463
+ if(time){
464
+ const dat = await this.connection.getSignaturesForAddress(data.pubkey, "finalized");
465
+ newTicket.time = dat[0].blockTime;
466
+ }
462
467
  tickets.push(newTicket);
463
468
  i++;
464
469
  }
@@ -732,6 +737,7 @@ class Lottery extends EventEmitter {
732
737
  else if(log.includes("Program log: Memo ")){
733
738
  const parts = log.split(":booster:");
734
739
  item.message = parts[1].slice(0, -1).trim();
740
+ item.message = item.message.replace(new RegExp("\\\\", "g"), "");
735
741
  }
736
742
  else if(log.includes("Program log: Authority ")){
737
743
  item.authority = log.replace("Program log: Authority ","").trim();
@@ -741,6 +747,7 @@ class Lottery extends EventEmitter {
741
747
  const matchesAuthority = authority ? (item.authority && authority.publicKey.toString() === item.authority) : true;
742
748
  const matchesLotteryId = lotteryId ? (item.lotteryId !== undefined && lotteryId.toString() === item.lotteryId.toString()) : true;
743
749
  if(matchesAuthority && matchesLotteryId && item.amount >= 0.0001){
750
+ item.time = init.blockTime;
744
751
  item.signature = init.signature;
745
752
  result.push(item);
746
753
  }
@@ -767,6 +774,45 @@ class Lottery extends EventEmitter {
767
774
  catch (error) {return error;}
768
775
  }
769
776
 
777
+ /**
778
+ * @param {Number} limit - the results to request (max 1000)
779
+ * @param {String} until - until signature to stop at (optional)
780
+ * @returns {Array|Object} - Array of booster objects or grouped booster objects if group=true
781
+ */
782
+ async GetMessages(limit = 1000, until = null) {
783
+ try {
784
+ const result = [];
785
+ let allSignatures = [];
786
+ let lastSignature = null;
787
+ while (allSignatures.length < limit) {
788
+ const options = {limit: Math.min(1000, limit - allSignatures.length)};
789
+ if (lastSignature) {options.before = lastSignature;}
790
+ if (until) {options.until = until;}
791
+ const signatures = await this.connection.getSignaturesForAddress(this.program, options);
792
+ if (signatures.length === 0) break;
793
+ allSignatures.push(...signatures);
794
+ lastSignature = signatures[signatures.length - 1].signature;
795
+ if (signatures.length < options.limit) break;
796
+ }
797
+ for (const row of allSignatures) {
798
+ if (!row.err &&
799
+ row.confirmationStatus === "finalized" &&
800
+ row.memo &&
801
+ row.memo.includes(":booster:")) {
802
+ const memo = {
803
+ message: row.memo.split(":booster:")[1].trim(),
804
+ time: row.blockTime,
805
+ signature: row.signature
806
+ };
807
+ result.push(memo);
808
+ }
809
+ }
810
+ return result;
811
+ } catch (error) {
812
+ return error;
813
+ }
814
+ }
815
+
770
816
  }
771
817
 
772
818
  class LotteryManager {