solotto 1.0.6 → 1.0.8
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 +78 -77
- package/package.json +1 -1
- package/solotto.d.ts +48 -46
- package/solotto.js +143 -131
package/README.md
CHANGED
|
@@ -19,11 +19,11 @@ A JavaScript SDK for interacting with the Solotto on-chain lottery program on So
|
|
|
19
19
|
- [RandomDraw](#randomdraw)
|
|
20
20
|
- [LockLottery](#locklottery)
|
|
21
21
|
- [ClaimExpired](#claimexpired)
|
|
22
|
-
- [Boost](#boost)
|
|
23
|
-
- [GetBoosters](#getboosters)
|
|
24
22
|
- [Lottery](#lottery-api)
|
|
25
23
|
- [BuyTickets](#buytickets)
|
|
26
24
|
- [ClaimTicket](#claimticket)
|
|
25
|
+
- [Boost](#boost)
|
|
26
|
+
- [GetBoosters](#getboosters)
|
|
27
27
|
- [GetLottery](#getlottery)
|
|
28
28
|
- [GetTicket](#getticket)
|
|
29
29
|
- [GetTickets](#gettickets)
|
|
@@ -72,8 +72,8 @@ Solotto is organized into three exported classes, each handling a different laye
|
|
|
72
72
|
|
|
73
73
|
| Class | Role |
|
|
74
74
|
|---|---|
|
|
75
|
-
| **`LotteryManager`** | Admin operations — initialize lotteries, trigger draws, lock/unlock ticket sales. |
|
|
76
|
-
| **`Lottery`** | Player & read operations — buy tickets, claim prizes, query lottery/ticket state, watch draws via WebSocket. |
|
|
75
|
+
| **`LotteryManager`** | Admin operations — initialize lotteries, trigger draws, lock/unlock ticket sales, reclaim expired prizes. |
|
|
76
|
+
| **`Lottery`** | Player & read operations — buy tickets, claim prizes, boost prize pools, query lottery/ticket/booster state, watch draws via WebSocket. |
|
|
77
77
|
| **`LotteryNetwork`** | Low-level transaction utilities — build, simulate, send, and confirm transactions with automatic compute budget and priority fee estimation. |
|
|
78
78
|
|
|
79
79
|
---
|
|
@@ -219,16 +219,77 @@ const result = await manager.ClaimExpired(authority, lotteryId, encoded);
|
|
|
219
219
|
|
|
220
220
|
---
|
|
221
221
|
|
|
222
|
+
### Lottery API
|
|
223
|
+
|
|
224
|
+
#### BuyTickets
|
|
225
|
+
|
|
226
|
+
Purchases one or more tickets for a lottery. Supports buying up to 4 tickets in a single transaction.
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
const lottery = new Lottery(connection, false, programId);
|
|
230
|
+
|
|
231
|
+
const result = await lottery.BuyTickets(buyer, authority, lotteryId, amount, encoded);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
| Parameter | Type | Default | Description |
|
|
235
|
+
|---|---|---|---|
|
|
236
|
+
| `buyer` | `Keypair` | — | The keypair of the ticket buyer. |
|
|
237
|
+
| `authority` | `Keypair \| {publicKey}` | — | The lottery authority (only `publicKey` is needed). |
|
|
238
|
+
| `lotteryId` | `Number` | — | The lottery ID to buy tickets for. |
|
|
239
|
+
| `amount` | `Number` | `1` | Number of tickets to purchase (1–4). |
|
|
240
|
+
| `encoded` | `Boolean` | `false` | If `true`, returns encoded transaction. |
|
|
241
|
+
|
|
242
|
+
**Returns:** `"finalized"` on success, `"Lottery is not active, no tickets can be sold"` if the lottery is inactive, or the transaction object when encoded.
|
|
243
|
+
|
|
244
|
+
**Example:**
|
|
245
|
+
|
|
246
|
+
```js
|
|
247
|
+
import { Connection, PublicKey, Keypair } from "@solana/web3.js";
|
|
248
|
+
import { Lottery } from "solotto";
|
|
249
|
+
|
|
250
|
+
const connection = new Connection("https://api.mainnet-beta.solana.com");
|
|
251
|
+
const programId = new PublicKey("YOUR_PROGRAM_ID");
|
|
252
|
+
const lottery = new Lottery(connection, false, programId);
|
|
253
|
+
|
|
254
|
+
const buyer = Keypair.generate();
|
|
255
|
+
const authority = { publicKey: new PublicKey("LOTTERY_AUTHORITY_PUBKEY") };
|
|
256
|
+
|
|
257
|
+
// Buy 2 tickets for lottery #1
|
|
258
|
+
const result = await lottery.BuyTickets(buyer, authority, 1, 2);
|
|
259
|
+
console.log(result); // "finalized"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
#### ClaimTicket
|
|
265
|
+
|
|
266
|
+
Claims the prize for the winning ticket. Must be called by the ticket owner.
|
|
267
|
+
|
|
268
|
+
```js
|
|
269
|
+
const result = await lottery.ClaimTicket(authority, lotteryId, winner, encoded);
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
| Parameter | Type | Default | Description |
|
|
273
|
+
|---|---|---|---|
|
|
274
|
+
| `authority` | `{publicKey}` | — | The lottery authority (only `publicKey` is needed). |
|
|
275
|
+
| `lotteryId` | `Number` | — | The lottery ID. |
|
|
276
|
+
| `winner` | `Keypair` | — | The keypair of the winning ticket's owner. |
|
|
277
|
+
| `encoded` | `Boolean` | `false` | If `true`, returns encoded transaction. |
|
|
278
|
+
|
|
279
|
+
**Returns:** `"finalized"` on success, the simulation log array (`string[]`) if the transaction fails simulation, or the transaction object when encoded.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
222
283
|
#### Boost
|
|
223
284
|
|
|
224
285
|
Boosts a lottery's prize pool by transferring SOL from any wallet. Can be called by anyone, not just the authority. Optionally attaches a memo message to the transaction.
|
|
225
286
|
|
|
226
287
|
```js
|
|
227
288
|
// Boost lottery #1 with 0.5 SOL
|
|
228
|
-
const result = await
|
|
289
|
+
const result = await lottery.Boost(authority, lotteryId, booster, 0.5);
|
|
229
290
|
|
|
230
291
|
// Boost with a memo message
|
|
231
|
-
const result = await
|
|
292
|
+
const result = await lottery.Boost(authority, lotteryId, booster, 1.0, "Good luck everyone!");
|
|
232
293
|
```
|
|
233
294
|
|
|
234
295
|
| Parameter | Type | Default | Description |
|
|
@@ -242,23 +303,23 @@ const result = await manager.Boost(authority, lotteryId, booster, 1.0, "Good luc
|
|
|
242
303
|
|
|
243
304
|
**Returns:** `"boosted"` on success, `"Draw initiated, cannot boost this prize pool"` if the draw has already started, or the transaction object when encoded.
|
|
244
305
|
|
|
245
|
-
> **Note:** When a `message` is provided, the SDK
|
|
306
|
+
> **Note:** When a `message` is provided, the SDK prepends `:booster:` to the memo string. This tag is used by `GetBoosters` to identify boost transactions when scanning on-chain history.
|
|
246
307
|
|
|
247
308
|
---
|
|
248
309
|
|
|
249
310
|
#### GetBoosters
|
|
250
311
|
|
|
251
|
-
Retrieves boost history by scanning on-chain
|
|
312
|
+
Retrieves boost history by scanning on-chain program logs for boost transactions. Filters out errored and non-finalized transactions, and only includes boosts of at least 0.0001 SOL. Can filter by authority, lottery ID, or both, and optionally group results by booster wallet address.
|
|
252
313
|
|
|
253
314
|
```js
|
|
254
315
|
// Get all boosters for a specific lottery
|
|
255
|
-
const boosters = await
|
|
316
|
+
const boosters = await lottery.GetBoosters(authority, lotteryId);
|
|
256
317
|
|
|
257
318
|
// Get all boosters across all lotteries (up to 500 transactions)
|
|
258
|
-
const allBoosters = await
|
|
319
|
+
const allBoosters = await lottery.GetBoosters(false, false, false, 500);
|
|
259
320
|
|
|
260
321
|
// Get boosters grouped by wallet address
|
|
261
|
-
const grouped = await
|
|
322
|
+
const grouped = await lottery.GetBoosters(authority, lotteryId, true);
|
|
262
323
|
```
|
|
263
324
|
|
|
264
325
|
| Parameter | Type | Default | Description |
|
|
@@ -273,10 +334,11 @@ const grouped = await manager.GetBoosters(authority, lotteryId, true);
|
|
|
273
334
|
```js
|
|
274
335
|
[
|
|
275
336
|
{
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
amount: 0.5,
|
|
337
|
+
booster: "Pubkey...", // Booster wallet public key
|
|
338
|
+
lotteryId: 1, // Lottery ID
|
|
339
|
+
authority: "Pubkey...", // Lottery authority public key
|
|
340
|
+
amount: 0.5, // Boost amount in SOL
|
|
341
|
+
message: "Good luck!", // Optional memo message (empty string if none)
|
|
280
342
|
signature: "TxSignature...",
|
|
281
343
|
},
|
|
282
344
|
// ...
|
|
@@ -289,7 +351,7 @@ const grouped = await manager.GetBoosters(authority, lotteryId, true);
|
|
|
289
351
|
{
|
|
290
352
|
"BoosterPubkey...": {
|
|
291
353
|
boost: [
|
|
292
|
-
{
|
|
354
|
+
{ booster: "Pubkey...", lotteryId: 1, authority: "Pubkey...", amount: 0.5, message: "...", signature: "TxSig..." },
|
|
293
355
|
// ...
|
|
294
356
|
],
|
|
295
357
|
total: 1.5, // Sum of all boost amounts in SOL
|
|
@@ -301,67 +363,6 @@ const grouped = await manager.GetBoosters(authority, lotteryId, true);
|
|
|
301
363
|
|
|
302
364
|
---
|
|
303
365
|
|
|
304
|
-
### Lottery API
|
|
305
|
-
|
|
306
|
-
#### BuyTickets
|
|
307
|
-
|
|
308
|
-
Purchases one or more tickets for a lottery. Supports buying up to 4 tickets in a single transaction.
|
|
309
|
-
|
|
310
|
-
```js
|
|
311
|
-
const lottery = new Lottery(connection, false, programId);
|
|
312
|
-
|
|
313
|
-
const result = await lottery.BuyTickets(buyer, authority, lotteryId, amount, encoded);
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
| Parameter | Type | Default | Description |
|
|
317
|
-
|---|---|---|---|
|
|
318
|
-
| `buyer` | `Keypair` | — | The keypair of the ticket buyer. |
|
|
319
|
-
| `authority` | `Keypair \| {publicKey}` | — | The lottery authority (only `publicKey` is needed). |
|
|
320
|
-
| `lotteryId` | `Number` | — | The lottery ID to buy tickets for. |
|
|
321
|
-
| `amount` | `Number` | `1` | Number of tickets to purchase (1–4). |
|
|
322
|
-
| `encoded` | `Boolean` | `false` | If `true`, returns encoded transaction. |
|
|
323
|
-
|
|
324
|
-
**Returns:** `"finalized"` on success, `"Lottery is not active, no tickets can be sold"` if the lottery is inactive, or the transaction object when encoded.
|
|
325
|
-
|
|
326
|
-
**Example:**
|
|
327
|
-
|
|
328
|
-
```js
|
|
329
|
-
import { Connection, PublicKey, Keypair } from "@solana/web3.js";
|
|
330
|
-
import { Lottery } from "solotto";
|
|
331
|
-
|
|
332
|
-
const connection = new Connection("https://api.mainnet-beta.solana.com");
|
|
333
|
-
const programId = new PublicKey("YOUR_PROGRAM_ID");
|
|
334
|
-
const lottery = new Lottery(connection, false, programId);
|
|
335
|
-
|
|
336
|
-
const buyer = Keypair.generate();
|
|
337
|
-
const authority = { publicKey: new PublicKey("LOTTERY_AUTHORITY_PUBKEY") };
|
|
338
|
-
|
|
339
|
-
// Buy 2 tickets for lottery #1
|
|
340
|
-
const result = await lottery.BuyTickets(buyer, authority, 1, 2);
|
|
341
|
-
console.log(result); // "finalized"
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
---
|
|
345
|
-
|
|
346
|
-
#### ClaimTicket
|
|
347
|
-
|
|
348
|
-
Claims the prize for the winning ticket. Must be called by the ticket owner.
|
|
349
|
-
|
|
350
|
-
```js
|
|
351
|
-
const result = await lottery.ClaimTicket(authority, lotteryId, winner, encoded);
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
| Parameter | Type | Default | Description |
|
|
355
|
-
|---|---|---|---|
|
|
356
|
-
| `authority` | `{publicKey}` | — | The lottery authority (only `publicKey` is needed). |
|
|
357
|
-
| `lotteryId` | `Number` | — | The lottery ID. |
|
|
358
|
-
| `winner` | `Keypair` | — | The keypair of the winning ticket's owner. |
|
|
359
|
-
| `encoded` | `Boolean` | `false` | If `true`, returns encoded transaction. |
|
|
360
|
-
|
|
361
|
-
**Returns:** `"finalized"` on success, the simulation log array (`string[]`) if the transaction fails simulation, or the transaction object when encoded.
|
|
362
|
-
|
|
363
|
-
---
|
|
364
|
-
|
|
365
366
|
#### GetLottery
|
|
366
367
|
|
|
367
368
|
Fetches the full on-chain state of a lottery.
|
package/package.json
CHANGED
package/solotto.d.ts
CHANGED
|
@@ -141,14 +141,16 @@ declare module "solotto" {
|
|
|
141
141
|
// ── Booster Types ──────────────────────────────────────────────────
|
|
142
142
|
|
|
143
143
|
interface BoosterRecord {
|
|
144
|
+
/** Booster wallet public key. */
|
|
145
|
+
booster: string;
|
|
144
146
|
/** Lottery numeric identifier. */
|
|
145
147
|
lotteryId: number;
|
|
146
148
|
/** Lottery authority public key. */
|
|
147
149
|
authority: string;
|
|
148
|
-
/** Booster wallet public key. */
|
|
149
|
-
booster: string;
|
|
150
150
|
/** Boost amount in SOL. */
|
|
151
151
|
amount: number;
|
|
152
|
+
/** Optional memo message from the booster. */
|
|
153
|
+
message: string;
|
|
152
154
|
/** Transaction signature. */
|
|
153
155
|
signature: string;
|
|
154
156
|
}
|
|
@@ -288,6 +290,50 @@ declare module "solotto" {
|
|
|
288
290
|
buyer?: HasPublicKey | false
|
|
289
291
|
): Promise<TicketListResult>;
|
|
290
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Boost a lottery's prize pool by transferring SOL from any wallet.
|
|
295
|
+
* @param authority - The lottery authority (only `publicKey` needed).
|
|
296
|
+
* @param lotteryId - Lottery numeric identifier.
|
|
297
|
+
* @param booster - The keypair of the wallet sending the boost.
|
|
298
|
+
* @param amount - Amount of SOL to boost (e.g. `0.5` for 0.5 SOL).
|
|
299
|
+
* @param message - Optional memo string attached to the transaction.
|
|
300
|
+
* @param encoded - If `true`, return a base64-encoded transaction.
|
|
301
|
+
*/
|
|
302
|
+
Boost(
|
|
303
|
+
authority: HasPublicKey,
|
|
304
|
+
lotteryId: number,
|
|
305
|
+
booster: Keypair,
|
|
306
|
+
amount: number,
|
|
307
|
+
message?: string | false,
|
|
308
|
+
encoded?: boolean
|
|
309
|
+
): Promise<string | TxResult | undefined>;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Retrieve boost history from on-chain program logs.
|
|
313
|
+
* @param authority - Filter by lottery authority, or `false` for all.
|
|
314
|
+
* @param lotteryId - Filter by lottery ID, or `false` for all.
|
|
315
|
+
* @param group - If `true`, group results by booster wallet address.
|
|
316
|
+
* @param limit - Maximum number of recent transactions to scan (max 1000).
|
|
317
|
+
*/
|
|
318
|
+
GetBoosters(
|
|
319
|
+
authority?: HasPublicKey | false,
|
|
320
|
+
lotteryId?: number | false,
|
|
321
|
+
group?: false,
|
|
322
|
+
limit?: number
|
|
323
|
+
): Promise<BoosterRecord[]>;
|
|
324
|
+
GetBoosters(
|
|
325
|
+
authority: HasPublicKey | false,
|
|
326
|
+
lotteryId: number | false,
|
|
327
|
+
group: true,
|
|
328
|
+
limit?: number
|
|
329
|
+
): Promise<GroupedBoostersResult>;
|
|
330
|
+
GetBoosters(
|
|
331
|
+
authority?: HasPublicKey | false,
|
|
332
|
+
lotteryId?: number | false,
|
|
333
|
+
group?: boolean,
|
|
334
|
+
limit?: number
|
|
335
|
+
): Promise<BoosterRecord[] | GroupedBoostersResult>;
|
|
336
|
+
|
|
291
337
|
/** Derive the lottery PDA. */
|
|
292
338
|
DeriveLotteryPDA(
|
|
293
339
|
authority: PublicKey,
|
|
@@ -365,49 +411,5 @@ declare module "solotto" {
|
|
|
365
411
|
lotteryId: number,
|
|
366
412
|
encoded?: boolean
|
|
367
413
|
): Promise<LotteryState | string | TxResult | undefined>;
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Boost a lottery's prize pool by transferring SOL from any wallet.
|
|
371
|
-
* @param authority - The lottery authority (only `publicKey` needed).
|
|
372
|
-
* @param lotteryId - Lottery numeric identifier.
|
|
373
|
-
* @param booster - The keypair of the wallet sending the boost.
|
|
374
|
-
* @param amount - Amount of SOL to boost (e.g. `0.5` for 0.5 SOL).
|
|
375
|
-
* @param message - Optional memo string attached to the transaction.
|
|
376
|
-
* @param encoded - If `true`, return a base64-encoded transaction.
|
|
377
|
-
*/
|
|
378
|
-
Boost(
|
|
379
|
-
authority: HasPublicKey,
|
|
380
|
-
lotteryId: number,
|
|
381
|
-
booster: Keypair,
|
|
382
|
-
amount: number,
|
|
383
|
-
message?: string | false,
|
|
384
|
-
encoded?: boolean
|
|
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>;
|
|
412
414
|
}
|
|
413
415
|
}
|
package/solotto.js
CHANGED
|
@@ -574,6 +574,149 @@ class Lottery extends EventEmitter {
|
|
|
574
574
|
return PublicKey.findProgramAddressSync([Buffer.from("prize-pool")], this.program);
|
|
575
575
|
}
|
|
576
576
|
|
|
577
|
+
/**
|
|
578
|
+
* @param {Keypair} authority - Keypair
|
|
579
|
+
* @param {String} lotteryId - The lottery id
|
|
580
|
+
* @param {Keypair} booster - The booster's keypair
|
|
581
|
+
* @param {Number} amount - The amount of sol to boost
|
|
582
|
+
* @param {Boolean} encoded - true returns encoded transaction
|
|
583
|
+
*/
|
|
584
|
+
async Boost(authority, lotteryId, booster, amount, message = false, encoded = false) {
|
|
585
|
+
try{
|
|
586
|
+
async function boostData(lotId, amount) {
|
|
587
|
+
const lamports = parseInt(amount * LAMPORTS_PER_SOL);
|
|
588
|
+
const buffer = Buffer.alloc(17); // 1 byte discriminator + 1 bytes price + 8 bytes id
|
|
589
|
+
buffer.writeUInt8(INSTRUCTIONS.BOOST_LOTTERY, 0); // boostLottery discriminator
|
|
590
|
+
buffer.writeBigUInt64LE(BigInt(lotId), 1);
|
|
591
|
+
buffer.writeBigUInt64LE(BigInt(lamports), 9);
|
|
592
|
+
return buffer;
|
|
593
|
+
}
|
|
594
|
+
if(message){message = ":booster:"+message;}
|
|
595
|
+
const network = new LotteryNetwork(this.connection);
|
|
596
|
+
const [lotteryPDA] = await this.DeriveLotteryPDA(authority.publicKey, lotteryId);
|
|
597
|
+
const LOTTO = await this.GetLottery(authority, lotteryId);
|
|
598
|
+
const keys = [
|
|
599
|
+
{ pubkey: booster.publicKey, isSigner: true, isWritable: true },
|
|
600
|
+
{ pubkey: lotteryPDA, isSigner: false, isWritable: true },
|
|
601
|
+
{ pubkey: new PublicKey(LOTTO.prizePoolAddress), isSigner: false, isWritable: true },
|
|
602
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
603
|
+
];
|
|
604
|
+
const ix = new TransactionInstruction(
|
|
605
|
+
{programId: this.program, keys, data: await boostData(lotteryId, amount)}
|
|
606
|
+
);
|
|
607
|
+
const _tx_ = {};
|
|
608
|
+
_tx_.account = booster.publicKey.toString(); // string : required
|
|
609
|
+
_tx_.instructions = [ix]; // array : required
|
|
610
|
+
_tx_.signers = false; // array : default false
|
|
611
|
+
_tx_.table = false; // array : default false
|
|
612
|
+
_tx_.tolerance = 1.2; // int : default 1.1
|
|
613
|
+
_tx_.compute = true; // bool : default true
|
|
614
|
+
_tx_.fees = true; // bool : default true
|
|
615
|
+
_tx_.priority = "Low"; // string : default Low
|
|
616
|
+
_tx_.memo = message;
|
|
617
|
+
if(encoded){
|
|
618
|
+
_tx_.serialize = true;
|
|
619
|
+
_tx_.encode = true;
|
|
620
|
+
}
|
|
621
|
+
else{
|
|
622
|
+
_tx_.serialize = false;
|
|
623
|
+
_tx_.encode = false;
|
|
624
|
+
}
|
|
625
|
+
const tx = await network.Tx(_tx_);
|
|
626
|
+
if(tx.logs && tx.logs.includes("Program log: Lottery draw has been initiated, cannot boost prize pool")){
|
|
627
|
+
return "Draw initiated, cannot boost this prize pool";
|
|
628
|
+
}
|
|
629
|
+
if(tx.status !== "ok"){return tx;}
|
|
630
|
+
if(booster.secretKey && !encoded){
|
|
631
|
+
tx.transaction.sign([booster]);
|
|
632
|
+
const sig = await network.Send(tx.transaction);
|
|
633
|
+
console.log("Signature:", sig);
|
|
634
|
+
const status = await network.Status(sig);
|
|
635
|
+
if(status == "finalized"){
|
|
636
|
+
return "boosted";
|
|
637
|
+
}
|
|
638
|
+
else{return status;}
|
|
639
|
+
}
|
|
640
|
+
else{return tx;}
|
|
641
|
+
}
|
|
642
|
+
catch (error) {
|
|
643
|
+
console.log(error);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* @param {Keypair} authority - Keypair
|
|
649
|
+
* @param {Number} lotteryId - The lottery id
|
|
650
|
+
* @param {Boolean} group - if true, groups results by booster wallet address
|
|
651
|
+
* @param {Number} limit - the results to request (max 1000)
|
|
652
|
+
* @returns {Array|Object} - Array of booster objects or grouped booster objects if group=true
|
|
653
|
+
*/
|
|
654
|
+
async GetBoosters(authority=false, lotteryId=false, group=false, limit=1000) {
|
|
655
|
+
try{
|
|
656
|
+
const initial = [];
|
|
657
|
+
const result = [];
|
|
658
|
+
const signatures = await this.connection.getSignaturesForAddress(this.program, {limit: limit,});
|
|
659
|
+
for await (const row of signatures) {
|
|
660
|
+
if(!row.err && row.confirmationStatus=="finalized" && row.memo && row.memo.includes(":booster:")){
|
|
661
|
+
initial.push(row);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
for await (const init of initial) {
|
|
665
|
+
const tx = await this.connection.getTransaction(init.signature,{maxSupportedTransactionVersion:0});
|
|
666
|
+
const logs = tx.meta.logMessages;
|
|
667
|
+
const item = {};
|
|
668
|
+
let isBooster = false;
|
|
669
|
+
for await (const log of logs){if(log.includes("Program log: Boosted by")){isBooster=true;}}
|
|
670
|
+
if(!isBooster){continue;}
|
|
671
|
+
for await (const log of logs) {
|
|
672
|
+
if(log.includes("Program log: Boosted by ")){
|
|
673
|
+
item.booster = log.replace("Program log: Boosted by ","").trim();
|
|
674
|
+
}
|
|
675
|
+
else if(log.includes("Program log: Lottery ID ")){
|
|
676
|
+
item.lotteryId = Number(log.replace("Program log: Lottery ID ","").trim());
|
|
677
|
+
}
|
|
678
|
+
else if(log.includes("Program log: Boost amount: ")){
|
|
679
|
+
const data = log.replace("Program log: Boost amount: ","").trim();
|
|
680
|
+
item.amount = parseFloat(data.split(" SOL ")[0]);
|
|
681
|
+
}
|
|
682
|
+
else if(log.includes("Program log: Memo ")){
|
|
683
|
+
const parts = log.split(":booster:");
|
|
684
|
+
item.message = parts[1].slice(0, -1).trim();
|
|
685
|
+
}
|
|
686
|
+
else if(log.includes("Program log: Authority ")){
|
|
687
|
+
item.authority = log.replace("Program log: Authority ","").trim();
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
// Apply filters with safety checks
|
|
691
|
+
const matchesAuthority = authority ? (item.authority && authority.publicKey.toString() === item.authority) : true;
|
|
692
|
+
const matchesLotteryId = lotteryId ? (item.lotteryId !== undefined && lotteryId.toString() === item.lotteryId.toString()) : true;
|
|
693
|
+
if(matchesAuthority && matchesLotteryId && item.amount >= 0.0001){
|
|
694
|
+
item.signature = init.signature;
|
|
695
|
+
result.push(item);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
// Group by booster if requested
|
|
699
|
+
if (group) {
|
|
700
|
+
const grouped = {};
|
|
701
|
+
result.forEach(item => {
|
|
702
|
+
if (!grouped[item.booster]) {
|
|
703
|
+
grouped[item.booster] = {
|
|
704
|
+
boost: [],
|
|
705
|
+
total: 0,
|
|
706
|
+
count: 0
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
grouped[item.booster].boost.push(item);
|
|
710
|
+
grouped[item.booster].total += item.amount;
|
|
711
|
+
grouped[item.booster].count = grouped[item.booster].boost.length;
|
|
712
|
+
});
|
|
713
|
+
return grouped;
|
|
714
|
+
}
|
|
715
|
+
return result;
|
|
716
|
+
}
|
|
717
|
+
catch (error) {return error;}
|
|
718
|
+
}
|
|
719
|
+
|
|
577
720
|
}
|
|
578
721
|
|
|
579
722
|
class LotteryManager {
|
|
@@ -823,137 +966,6 @@ class LotteryManager {
|
|
|
823
966
|
}
|
|
824
967
|
}
|
|
825
968
|
|
|
826
|
-
/**
|
|
827
|
-
* @param {Keypair} authority - Keypair
|
|
828
|
-
* @param {String} lotteryId - The lottery id
|
|
829
|
-
* @param {Keypair} booster - The booster's keypair
|
|
830
|
-
* @param {Number} amount - The amount of sol to boost
|
|
831
|
-
* @param {Boolean} encoded - true returns encoded transaction
|
|
832
|
-
*/
|
|
833
|
-
async Boost(authority, lotteryId, booster, amount, message = false, encoded = false) {
|
|
834
|
-
try{
|
|
835
|
-
async function boostData(lotId, amount) {
|
|
836
|
-
const lamports = parseInt(amount * LAMPORTS_PER_SOL);
|
|
837
|
-
const buffer = Buffer.alloc(17); // 1 byte discriminator + 1 bytes price + 8 bytes id
|
|
838
|
-
buffer.writeUInt8(INSTRUCTIONS.BOOST_LOTTERY, 0); // boostLottery discriminator
|
|
839
|
-
buffer.writeBigUInt64LE(BigInt(lotId), 1);
|
|
840
|
-
buffer.writeBigUInt64LE(BigInt(lamports), 9);
|
|
841
|
-
return buffer;
|
|
842
|
-
}
|
|
843
|
-
if(message){
|
|
844
|
-
message = ":booster:"+authority.publicKey.toString()+","+lotteryId+","+booster.publicKey.toString()+","+amount+":booster:"+message;
|
|
845
|
-
}
|
|
846
|
-
const lottery = new Lottery(this.connection, false, this.program);
|
|
847
|
-
const network = new LotteryNetwork(this.connection);
|
|
848
|
-
const [lotteryPDA] = await lottery.DeriveLotteryPDA(authority.publicKey, lotteryId);
|
|
849
|
-
const LOTTO = await lottery.GetLottery(authority, lotteryId);
|
|
850
|
-
const keys = [
|
|
851
|
-
{ pubkey: booster.publicKey, isSigner: true, isWritable: true },
|
|
852
|
-
{ pubkey: lotteryPDA, isSigner: false, isWritable: true },
|
|
853
|
-
{ pubkey: new PublicKey(LOTTO.prizePoolAddress), isSigner: false, isWritable: true },
|
|
854
|
-
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
855
|
-
];
|
|
856
|
-
const ix = new TransactionInstruction(
|
|
857
|
-
{programId: this.program, keys, data: await boostData(lotteryId, amount)}
|
|
858
|
-
);
|
|
859
|
-
const _tx_ = {};
|
|
860
|
-
_tx_.account = booster.publicKey.toString(); // string : required
|
|
861
|
-
_tx_.instructions = [ix]; // array : required
|
|
862
|
-
_tx_.signers = false; // array : default false
|
|
863
|
-
_tx_.table = false; // array : default false
|
|
864
|
-
_tx_.tolerance = 1.2; // int : default 1.1
|
|
865
|
-
_tx_.compute = true; // bool : default true
|
|
866
|
-
_tx_.fees = true; // bool : default true
|
|
867
|
-
_tx_.priority = "Low"; // string : default Low
|
|
868
|
-
_tx_.memo = message;
|
|
869
|
-
if(encoded){
|
|
870
|
-
_tx_.serialize = true;
|
|
871
|
-
_tx_.encode = true;
|
|
872
|
-
}
|
|
873
|
-
else{
|
|
874
|
-
_tx_.serialize = false;
|
|
875
|
-
_tx_.encode = false;
|
|
876
|
-
}
|
|
877
|
-
const tx = await network.Tx(_tx_);
|
|
878
|
-
if(tx.logs && tx.logs.includes("Program log: Lottery draw has been initiated, cannot boost prize pool")){
|
|
879
|
-
return "Draw initiated, cannot boost this prize pool";
|
|
880
|
-
}
|
|
881
|
-
if(tx.status !== "ok"){return tx;}
|
|
882
|
-
if(booster.secretKey && !encoded){
|
|
883
|
-
tx.transaction.sign([booster]);
|
|
884
|
-
const sig = await network.Send(tx.transaction);
|
|
885
|
-
console.log("Signature:", sig);
|
|
886
|
-
const status = await network.Status(sig);
|
|
887
|
-
if(status == "finalized"){
|
|
888
|
-
return "boosted";
|
|
889
|
-
}
|
|
890
|
-
else{return status;}
|
|
891
|
-
}
|
|
892
|
-
else{return tx;}
|
|
893
|
-
}
|
|
894
|
-
catch (error) {
|
|
895
|
-
console.log(error);
|
|
896
|
-
}
|
|
897
|
-
}
|
|
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
|
-
|
|
957
969
|
}
|
|
958
970
|
|
|
959
971
|
export {
|