solotto 1.0.7 → 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 +70 -70
- package/package.json +1 -1
- package/solotto.d.ts +44 -44
- package/solotto.js +143 -144
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 |
|
|
@@ -252,13 +313,13 @@ Retrieves boost history by scanning on-chain program logs for boost transactions
|
|
|
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 |
|
|
@@ -302,67 +363,6 @@ const grouped = await manager.GetBoosters(authority, lotteryId, true);
|
|
|
302
363
|
|
|
303
364
|
---
|
|
304
365
|
|
|
305
|
-
### Lottery API
|
|
306
|
-
|
|
307
|
-
#### BuyTickets
|
|
308
|
-
|
|
309
|
-
Purchases one or more tickets for a lottery. Supports buying up to 4 tickets in a single transaction.
|
|
310
|
-
|
|
311
|
-
```js
|
|
312
|
-
const lottery = new Lottery(connection, false, programId);
|
|
313
|
-
|
|
314
|
-
const result = await lottery.BuyTickets(buyer, authority, lotteryId, amount, encoded);
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
| Parameter | Type | Default | Description |
|
|
318
|
-
|---|---|---|---|
|
|
319
|
-
| `buyer` | `Keypair` | — | The keypair of the ticket buyer. |
|
|
320
|
-
| `authority` | `Keypair \| {publicKey}` | — | The lottery authority (only `publicKey` is needed). |
|
|
321
|
-
| `lotteryId` | `Number` | — | The lottery ID to buy tickets for. |
|
|
322
|
-
| `amount` | `Number` | `1` | Number of tickets to purchase (1–4). |
|
|
323
|
-
| `encoded` | `Boolean` | `false` | If `true`, returns encoded transaction. |
|
|
324
|
-
|
|
325
|
-
**Returns:** `"finalized"` on success, `"Lottery is not active, no tickets can be sold"` if the lottery is inactive, or the transaction object when encoded.
|
|
326
|
-
|
|
327
|
-
**Example:**
|
|
328
|
-
|
|
329
|
-
```js
|
|
330
|
-
import { Connection, PublicKey, Keypair } from "@solana/web3.js";
|
|
331
|
-
import { Lottery } from "solotto";
|
|
332
|
-
|
|
333
|
-
const connection = new Connection("https://api.mainnet-beta.solana.com");
|
|
334
|
-
const programId = new PublicKey("YOUR_PROGRAM_ID");
|
|
335
|
-
const lottery = new Lottery(connection, false, programId);
|
|
336
|
-
|
|
337
|
-
const buyer = Keypair.generate();
|
|
338
|
-
const authority = { publicKey: new PublicKey("LOTTERY_AUTHORITY_PUBKEY") };
|
|
339
|
-
|
|
340
|
-
// Buy 2 tickets for lottery #1
|
|
341
|
-
const result = await lottery.BuyTickets(buyer, authority, 1, 2);
|
|
342
|
-
console.log(result); // "finalized"
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
---
|
|
346
|
-
|
|
347
|
-
#### ClaimTicket
|
|
348
|
-
|
|
349
|
-
Claims the prize for the winning ticket. Must be called by the ticket owner.
|
|
350
|
-
|
|
351
|
-
```js
|
|
352
|
-
const result = await lottery.ClaimTicket(authority, lotteryId, winner, encoded);
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
| Parameter | Type | Default | Description |
|
|
356
|
-
|---|---|---|---|
|
|
357
|
-
| `authority` | `{publicKey}` | — | The lottery authority (only `publicKey` is needed). |
|
|
358
|
-
| `lotteryId` | `Number` | — | The lottery ID. |
|
|
359
|
-
| `winner` | `Keypair` | — | The keypair of the winning ticket's owner. |
|
|
360
|
-
| `encoded` | `Boolean` | `false` | If `true`, returns encoded transaction. |
|
|
361
|
-
|
|
362
|
-
**Returns:** `"finalized"` on success, the simulation log array (`string[]`) if the transaction fails simulation, or the transaction object when encoded.
|
|
363
|
-
|
|
364
|
-
---
|
|
365
|
-
|
|
366
366
|
#### GetLottery
|
|
367
367
|
|
|
368
368
|
Fetches the full on-chain state of a lottery.
|
package/package.json
CHANGED
package/solotto.d.ts
CHANGED
|
@@ -290,6 +290,50 @@ declare module "solotto" {
|
|
|
290
290
|
buyer?: HasPublicKey | false
|
|
291
291
|
): Promise<TicketListResult>;
|
|
292
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
|
+
|
|
293
337
|
/** Derive the lottery PDA. */
|
|
294
338
|
DeriveLotteryPDA(
|
|
295
339
|
authority: PublicKey,
|
|
@@ -367,49 +411,5 @@ declare module "solotto" {
|
|
|
367
411
|
lotteryId: number,
|
|
368
412
|
encoded?: boolean
|
|
369
413
|
): Promise<LotteryState | string | TxResult | undefined>;
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Boost a lottery's prize pool by transferring SOL from any wallet.
|
|
373
|
-
* @param authority - The lottery authority (only `publicKey` needed).
|
|
374
|
-
* @param lotteryId - Lottery numeric identifier.
|
|
375
|
-
* @param booster - The keypair of the wallet sending the boost.
|
|
376
|
-
* @param amount - Amount of SOL to boost (e.g. `0.5` for 0.5 SOL).
|
|
377
|
-
* @param message - Optional memo string attached to the transaction.
|
|
378
|
-
* @param encoded - If `true`, return a base64-encoded transaction.
|
|
379
|
-
*/
|
|
380
|
-
Boost(
|
|
381
|
-
authority: HasPublicKey,
|
|
382
|
-
lotteryId: number,
|
|
383
|
-
booster: Keypair,
|
|
384
|
-
amount: number,
|
|
385
|
-
message?: string | false,
|
|
386
|
-
encoded?: boolean
|
|
387
|
-
): Promise<string | TxResult | undefined>;
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Retrieve boost history from on-chain transaction memos.
|
|
391
|
-
* @param authority - Filter by lottery authority, or `false` for all.
|
|
392
|
-
* @param lotteryId - Filter by lottery ID, or `false` for all.
|
|
393
|
-
* @param group - If `true`, group results by booster wallet address.
|
|
394
|
-
* @param limit - Maximum number of recent transactions to scan (max 1000).
|
|
395
|
-
*/
|
|
396
|
-
GetBoosters(
|
|
397
|
-
authority?: HasPublicKey | false,
|
|
398
|
-
lotteryId?: number | false,
|
|
399
|
-
group?: false,
|
|
400
|
-
limit?: number
|
|
401
|
-
): Promise<BoosterRecord[]>;
|
|
402
|
-
GetBoosters(
|
|
403
|
-
authority: HasPublicKey | false,
|
|
404
|
-
lotteryId: number | false,
|
|
405
|
-
group: true,
|
|
406
|
-
limit?: number
|
|
407
|
-
): Promise<GroupedBoostersResult>;
|
|
408
|
-
GetBoosters(
|
|
409
|
-
authority?: HasPublicKey | false,
|
|
410
|
-
lotteryId?: number | false,
|
|
411
|
-
group?: boolean,
|
|
412
|
-
limit?: number
|
|
413
|
-
): Promise<BoosterRecord[] | GroupedBoostersResult>;
|
|
414
414
|
}
|
|
415
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,150 +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){message = ":booster:"+message;}
|
|
844
|
-
const lottery = new Lottery(this.connection, false, this.program);
|
|
845
|
-
const network = new LotteryNetwork(this.connection);
|
|
846
|
-
const [lotteryPDA] = await lottery.DeriveLotteryPDA(authority.publicKey, lotteryId);
|
|
847
|
-
const LOTTO = await lottery.GetLottery(authority, lotteryId);
|
|
848
|
-
const keys = [
|
|
849
|
-
{ pubkey: booster.publicKey, isSigner: true, isWritable: true },
|
|
850
|
-
{ pubkey: lotteryPDA, isSigner: false, isWritable: true },
|
|
851
|
-
{ pubkey: new PublicKey(LOTTO.prizePoolAddress), isSigner: false, isWritable: true },
|
|
852
|
-
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
853
|
-
];
|
|
854
|
-
const ix = new TransactionInstruction(
|
|
855
|
-
{programId: this.program, keys, data: await boostData(lotteryId, amount)}
|
|
856
|
-
);
|
|
857
|
-
const _tx_ = {};
|
|
858
|
-
_tx_.account = booster.publicKey.toString(); // string : required
|
|
859
|
-
_tx_.instructions = [ix]; // array : required
|
|
860
|
-
_tx_.signers = false; // array : default false
|
|
861
|
-
_tx_.table = false; // array : default false
|
|
862
|
-
_tx_.tolerance = 1.2; // int : default 1.1
|
|
863
|
-
_tx_.compute = true; // bool : default true
|
|
864
|
-
_tx_.fees = true; // bool : default true
|
|
865
|
-
_tx_.priority = "Low"; // string : default Low
|
|
866
|
-
_tx_.memo = message;
|
|
867
|
-
if(encoded){
|
|
868
|
-
_tx_.serialize = true;
|
|
869
|
-
_tx_.encode = true;
|
|
870
|
-
}
|
|
871
|
-
else{
|
|
872
|
-
_tx_.serialize = false;
|
|
873
|
-
_tx_.encode = false;
|
|
874
|
-
}
|
|
875
|
-
const tx = await network.Tx(_tx_);
|
|
876
|
-
if(tx.logs && tx.logs.includes("Program log: Lottery draw has been initiated, cannot boost prize pool")){
|
|
877
|
-
return "Draw initiated, cannot boost this prize pool";
|
|
878
|
-
}
|
|
879
|
-
if(tx.status !== "ok"){return tx;}
|
|
880
|
-
if(booster.secretKey && !encoded){
|
|
881
|
-
tx.transaction.sign([booster]);
|
|
882
|
-
const sig = await network.Send(tx.transaction);
|
|
883
|
-
console.log("Signature:", sig);
|
|
884
|
-
const status = await network.Status(sig);
|
|
885
|
-
if(status == "finalized"){
|
|
886
|
-
return "boosted";
|
|
887
|
-
}
|
|
888
|
-
else{return status;}
|
|
889
|
-
}
|
|
890
|
-
else{return tx;}
|
|
891
|
-
}
|
|
892
|
-
catch (error) {
|
|
893
|
-
console.log(error);
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
/**
|
|
898
|
-
* @param {Keypair} authority - Keypair
|
|
899
|
-
* @param {Number} lotteryId - The lottery id
|
|
900
|
-
* @param {Boolean} group - if true, groups results by booster wallet address
|
|
901
|
-
* @param {Number} limit - the results to request (max 1000)
|
|
902
|
-
* @returns {Array|Object} - Array of booster objects or grouped booster objects if group=true
|
|
903
|
-
*/
|
|
904
|
-
async GetBoosters(authority=false, lotteryId=false, group=false, limit=1000) {
|
|
905
|
-
try{
|
|
906
|
-
const initial = [];
|
|
907
|
-
const result = [];
|
|
908
|
-
const signatures = await this.connection.getSignaturesForAddress(this.program, {limit: limit,});
|
|
909
|
-
for await (const row of signatures) {
|
|
910
|
-
if(!row.err && row.confirmationStatus=="finalized" && row.memo && row.memo.includes(":booster:")){
|
|
911
|
-
initial.push(row);
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
for await (const init of initial) {
|
|
915
|
-
const tx = await this.connection.getTransaction(init.signature,{maxSupportedTransactionVersion:0});
|
|
916
|
-
const logs = tx.meta.logMessages;
|
|
917
|
-
const item = {};
|
|
918
|
-
let isBooster = false;
|
|
919
|
-
for await (const log of logs){if(log.includes("Program log: Boosted by")){isBooster=true;}}
|
|
920
|
-
if(!isBooster){continue;}
|
|
921
|
-
for await (const log of logs) {
|
|
922
|
-
if(log.includes("Program log: Boosted by ")){
|
|
923
|
-
item.booster = log.replace("Program log: Boosted by ","").trim();
|
|
924
|
-
}
|
|
925
|
-
else if(log.includes("Program log: Lottery ID ")){
|
|
926
|
-
item.lotteryId = Number(log.replace("Program log: Lottery ID ","").trim());
|
|
927
|
-
}
|
|
928
|
-
else if(log.includes("Program log: Boost amount: ")){
|
|
929
|
-
const data = log.replace("Program log: Boost amount: ","").trim();
|
|
930
|
-
item.amount = parseFloat(data.split(" SOL ")[0]);
|
|
931
|
-
}
|
|
932
|
-
else if(log.includes("Program log: Memo ")){
|
|
933
|
-
const parts = log.split(":booster:");
|
|
934
|
-
item.message = parts[1].slice(0, -1).trim();
|
|
935
|
-
}
|
|
936
|
-
else if(log.includes("Program log: Authority ")){
|
|
937
|
-
item.authority = log.replace("Program log: Authority ","").trim();
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
// Apply filters with safety checks
|
|
941
|
-
const matchesAuthority = authority ? (item.authority && authority.publicKey.toString() === item.authority) : true;
|
|
942
|
-
const matchesLotteryId = lotteryId ? (item.lotteryId !== undefined && lotteryId.toString() === item.lotteryId.toString()) : true;
|
|
943
|
-
if(matchesAuthority && matchesLotteryId && item.amount >= 0.0001){
|
|
944
|
-
item.signature = init.signature;
|
|
945
|
-
result.push(item);
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
// Group by booster if requested
|
|
949
|
-
if (group) {
|
|
950
|
-
const grouped = {};
|
|
951
|
-
result.forEach(item => {
|
|
952
|
-
if (!grouped[item.booster]) {
|
|
953
|
-
grouped[item.booster] = {
|
|
954
|
-
boost: [],
|
|
955
|
-
total: 0,
|
|
956
|
-
count: 0
|
|
957
|
-
};
|
|
958
|
-
}
|
|
959
|
-
grouped[item.booster].boost.push(item);
|
|
960
|
-
grouped[item.booster].total += item.amount;
|
|
961
|
-
grouped[item.booster].count = grouped[item.booster].boost.length;
|
|
962
|
-
});
|
|
963
|
-
return grouped;
|
|
964
|
-
}
|
|
965
|
-
return result;
|
|
966
|
-
}
|
|
967
|
-
catch (error) {return error;}
|
|
968
|
-
}
|
|
969
|
-
|
|
970
969
|
}
|
|
971
970
|
|
|
972
971
|
export {
|