solotto 1.0.5 → 1.0.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
@@ -20,6 +20,7 @@ A JavaScript SDK for interacting with the Solotto on-chain lottery program on So
20
20
  - [LockLottery](#locklottery)
21
21
  - [ClaimExpired](#claimexpired)
22
22
  - [Boost](#boost)
23
+ - [GetBoosters](#getboosters)
23
24
  - [Lottery](#lottery-api)
24
25
  - [BuyTickets](#buytickets)
25
26
  - [ClaimTicket](#claimticket)
@@ -241,6 +242,63 @@ const result = await manager.Boost(authority, lotteryId, booster, 1.0, "Good luc
241
242
 
242
243
  **Returns:** `"boosted"` on success, `"Draw initiated, cannot boost this prize pool"` if the draw has already started, or the transaction object when encoded.
243
244
 
245
+ > **Note:** When a `message` is provided, the SDK automatically prepends a structured memo in the format `:booster:authority,lotteryId,booster,amount:booster:` before your message. This structured prefix is used by `GetBoosters` to index boost history from on-chain transaction memos.
246
+
247
+ ---
248
+
249
+ #### GetBoosters
250
+
251
+ Retrieves boost history by scanning on-chain transaction memos. Can filter by authority, lottery ID, or both, and optionally group results by booster wallet address.
252
+
253
+ ```js
254
+ // Get all boosters for a specific lottery
255
+ const boosters = await manager.GetBoosters(authority, lotteryId);
256
+
257
+ // Get all boosters across all lotteries (up to 500 transactions)
258
+ const allBoosters = await manager.GetBoosters(false, false, false, 500);
259
+
260
+ // Get boosters grouped by wallet address
261
+ const grouped = await manager.GetBoosters(authority, lotteryId, true);
262
+ ```
263
+
264
+ | Parameter | Type | Default | Description |
265
+ |---|---|---|---|
266
+ | `authority` | `{publicKey} \| false` | `false` | Filter by lottery authority. Pass `false` to include all authorities. |
267
+ | `lotteryId` | `Number \| false` | `false` | Filter by lottery ID. Pass `false` to include all lotteries. |
268
+ | `group` | `Boolean` | `false` | If `true`, groups results by booster wallet address. |
269
+ | `limit` | `Number` | `1000` | Maximum number of recent transactions to scan (max 1000). |
270
+
271
+ **Returns (ungrouped):** An array of booster objects:
272
+
273
+ ```js
274
+ [
275
+ {
276
+ lotteryId: 1,
277
+ authority: "Pubkey...",
278
+ booster: "Pubkey...",
279
+ amount: 0.5,
280
+ signature: "TxSignature...",
281
+ },
282
+ // ...
283
+ ]
284
+ ```
285
+
286
+ **Returns (grouped, `group = true`):** An object keyed by booster wallet address:
287
+
288
+ ```js
289
+ {
290
+ "BoosterPubkey...": {
291
+ boost: [
292
+ { lotteryId: 1, authority: "Pubkey...", booster: "Pubkey...", amount: 0.5, signature: "TxSig..." },
293
+ // ...
294
+ ],
295
+ total: 1.5, // Sum of all boost amounts in SOL
296
+ count: 3, // Number of boosts
297
+ },
298
+ // ...
299
+ }
300
+ ```
301
+
244
302
  ---
245
303
 
246
304
  ### Lottery API
@@ -300,7 +358,7 @@ const result = await lottery.ClaimTicket(authority, lotteryId, winner, encoded);
300
358
  | `winner` | `Keypair` | — | The keypair of the winning ticket's owner. |
301
359
  | `encoded` | `Boolean` | `false` | If `true`, returns encoded transaction. |
302
360
 
303
- **Returns:** `"finalized"` on success, or the transaction object when encoded.
361
+ **Returns:** `"finalized"` on success, the simulation log array (`string[]`) if the transaction fails simulation, or the transaction object when encoded.
304
362
 
305
363
  ---
306
364
 
@@ -518,7 +576,7 @@ const status = await network.Status(signature, maxRetries, intervalSeconds);
518
576
 
519
577
  ## Transaction Modes
520
578
 
521
- Every write method (`Initialize`, `RandomDraw`, `LockLottery`, `BuyTickets`, `ClaimTicket`) supports two modes controlled by the `encoded` parameter:
579
+ Every write method (`Initialize`, `RandomDraw`, `LockLottery`, `ClaimExpired`, `Boost`, `BuyTickets`, `ClaimTicket`) supports two modes controlled by the `encoded` parameter:
522
580
 
523
581
  **Direct Mode** (`encoded = false`, default) — The SDK signs, sends, and confirms the transaction. Requires the keypair to have a `secretKey`. Returns the final status or lottery state.
524
582
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solotto",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Solana lottery client",
5
5
  "type": "module",
6
6
  "types": "./solotto.d.ts",
package/solotto.d.ts CHANGED
@@ -138,6 +138,34 @@ declare module "solotto" {
138
138
  reconnecting: (event: ReconnectingEvent) => void;
139
139
  }
140
140
 
141
+ // ── Booster Types ──────────────────────────────────────────────────
142
+
143
+ interface BoosterRecord {
144
+ /** Lottery numeric identifier. */
145
+ lotteryId: number;
146
+ /** Lottery authority public key. */
147
+ authority: string;
148
+ /** Booster wallet public key. */
149
+ booster: string;
150
+ /** Boost amount in SOL. */
151
+ amount: number;
152
+ /** Transaction signature. */
153
+ signature: string;
154
+ }
155
+
156
+ interface GroupedBooster {
157
+ /** Array of individual boost records. */
158
+ boost: BoosterRecord[];
159
+ /** Total SOL boosted by this wallet. */
160
+ total: number;
161
+ /** Number of boosts from this wallet. */
162
+ count: number;
163
+ }
164
+
165
+ interface GroupedBoostersResult {
166
+ [boosterAddress: string]: GroupedBooster;
167
+ }
168
+
141
169
  // ── Authority-like objects ────────────────────────────────────────────
142
170
 
143
171
  /** An object with at least a `publicKey` property (e.g. a Keypair without the secret key). */
@@ -237,7 +265,7 @@ declare module "solotto" {
237
265
  lotteryId: number,
238
266
  winner: Keypair,
239
267
  encoded?: boolean
240
- ): Promise<string | TxResult>;
268
+ ): Promise<string | string[] | TxResult>;
241
269
 
242
270
  /** Fetch the on-chain state of a lottery. */
243
271
  GetLottery(
@@ -355,5 +383,31 @@ declare module "solotto" {
355
383
  message?: string | false,
356
384
  encoded?: boolean
357
385
  ): Promise<string | TxResult | undefined>;
386
+
387
+ /**
388
+ * Retrieve boost history from on-chain transaction memos.
389
+ * @param authority - Filter by lottery authority, or `false` for all.
390
+ * @param lotteryId - Filter by lottery ID, or `false` for all.
391
+ * @param group - If `true`, group results by booster wallet address.
392
+ * @param limit - Maximum number of recent transactions to scan (max 1000).
393
+ */
394
+ GetBoosters(
395
+ authority?: HasPublicKey | false,
396
+ lotteryId?: number | false,
397
+ group?: false,
398
+ limit?: number
399
+ ): Promise<BoosterRecord[]>;
400
+ GetBoosters(
401
+ authority: HasPublicKey | false,
402
+ lotteryId: number | false,
403
+ group: true,
404
+ limit?: number
405
+ ): Promise<GroupedBoostersResult>;
406
+ GetBoosters(
407
+ authority?: HasPublicKey | false,
408
+ lotteryId?: number | false,
409
+ group?: boolean,
410
+ limit?: number
411
+ ): Promise<BoosterRecord[] | GroupedBoostersResult>;
358
412
  }
359
413
  }
package/solotto.js CHANGED
@@ -285,6 +285,9 @@ class Lottery extends EventEmitter {
285
285
  _tx_.encode = false;
286
286
  }
287
287
  const tx = await network.Tx(_tx_);
288
+ if(tx.logs){
289
+ return tx.logs;
290
+ }
288
291
  if(winner.secretKey && !encoded){
289
292
  tx.transaction.sign([winner]);
290
293
  const sig = await network.Send(tx.transaction);
@@ -837,6 +840,9 @@ class LotteryManager {
837
840
  buffer.writeBigUInt64LE(BigInt(lamports), 9);
838
841
  return buffer;
839
842
  }
843
+ if(message){
844
+ message = ":booster:"+authority.publicKey.toString()+","+lotteryId+","+booster.publicKey.toString()+","+amount+":booster:"+message;
845
+ }
840
846
  const lottery = new Lottery(this.connection, false, this.program);
841
847
  const network = new LotteryNetwork(this.connection);
842
848
  const [lotteryPDA] = await lottery.DeriveLotteryPDA(authority.publicKey, lotteryId);
@@ -890,6 +896,64 @@ class LotteryManager {
890
896
  }
891
897
  }
892
898
 
899
+ /**
900
+ * @param {Keypair} authority - Keypair
901
+ * @param {String} lotteryId - The lottery id
902
+ * @param {Boolean} group - if true, groups results by booster wallet address
903
+ * @param {Number} limit - the results to request (max 1000)
904
+ * @returns {Array|Object} - Array of booster objects or Object grouped by booster address
905
+ * Booster objects are returned if the transaction memo includes ":booster:" and matches the authority and lotteryId (if provided)
906
+ * Booster memo format: ":booster:authorityPublicKey,lotteryId,boosterPublicKey,amount:booster:optionalMessage"
907
+ * Example return object: { authority: "authorityPublicKey", lotteryId: "1", booster: "boosterPublicKey", amount: 1.5, signature: "transactionSignature" }
908
+ * If authority is provided, only boosters from that authority are returned
909
+ * If lotteryId is provided, only boosters for that lotteryId are returned
910
+ * If both authority and lotteryId are provided, only boosters matching both are returned
911
+ * If neither is provided, all boosters are returned up to the specified limit
912
+ * If group is true, returns object with booster addresses as keys, each containing array of boost objects and total amount
913
+ * Example grouped return: { "boosterPublicKey": { boost: [...], total: 5.5 } }
914
+ */
915
+ async GetBoosters(authority=false, lotteryId=false, group=false, limit=1000) {
916
+ try{
917
+ const result = [];
918
+ const signatures = await this.connection.getSignaturesForAddress(this.program, {limit: limit,});
919
+ for await (const row of signatures) {
920
+ if(row.memo && row.memo.includes(":booster:")){
921
+ const memo = row.memo.split(":booster:")[1];
922
+ const [auth, lotId, booster, amount] = memo.split(",");
923
+ if((authority ? authority.publicKey.toString() === auth : true) &&
924
+ (lotteryId ? lotteryId.toString() === lotId : true)
925
+ ){
926
+ result.push({
927
+ lotteryId: Number(lotId),
928
+ authority: auth,
929
+ booster: booster,
930
+ amount: parseFloat(amount),
931
+ signature: row.signature
932
+ });
933
+ }
934
+ }
935
+ }
936
+ if (group) {
937
+ const grouped = {};
938
+ result.forEach(item => {
939
+ if (!grouped[item.booster]) {
940
+ grouped[item.booster] = {
941
+ boost: [],
942
+ total: 0
943
+ }
944
+ }
945
+ grouped[item.booster].boost.push(item);
946
+ grouped[item.booster].total += item.amount;
947
+ grouped[item.booster].count = grouped[item.booster].boost.length;
948
+ });
949
+ return grouped;
950
+ }
951
+
952
+ return result;
953
+ }
954
+ catch (error) {return error;}
955
+ }
956
+
893
957
  }
894
958
 
895
959
  export {