solotto 1.0.0 → 1.0.2
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 +32 -2
- package/package.json +2 -1
- package/solotto.d.ts +325 -0
- package/solotto.js +6 -9
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ const manager = new LotteryManager(connection, programId);
|
|
|
98
98
|
|
|
99
99
|
### Lottery
|
|
100
100
|
|
|
101
|
-
Used by **players** to buy tickets and claim prizes, and by anyone to read lottery state.
|
|
101
|
+
Used by **players** to buy tickets and claim prizes, and by anyone to read lottery state. Extends `EventEmitter` to provide real-time draw notifications via `WatchDraw()`.
|
|
102
102
|
|
|
103
103
|
```js
|
|
104
104
|
import { Lottery } from "solotto";
|
|
@@ -368,12 +368,42 @@ const myTickets = await lottery.GetTickets(authority, lotteryId, buyer);
|
|
|
368
368
|
|
|
369
369
|
Opens a WebSocket subscription to listen for draw events in real time. Requires the `wss` parameter to be set in the `Lottery` constructor. Automatically reconnects on connection failure.
|
|
370
370
|
|
|
371
|
+
The `Lottery` class extends `EventEmitter`, so you subscribe to draw results and connection lifecycle events using standard `.on()` listeners.
|
|
372
|
+
|
|
371
373
|
```js
|
|
372
374
|
const lottery = new Lottery(connection, "wss://your-rpc.com", programId);
|
|
375
|
+
|
|
376
|
+
// Listen for draw results
|
|
377
|
+
lottery.on("draw", ({ winningTicketNumber, signature }) => {
|
|
378
|
+
console.log(`Winning ticket: #${winningTicketNumber}`);
|
|
379
|
+
console.log(`Transaction: ${signature}`);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// Connection lifecycle events (optional)
|
|
383
|
+
lottery.on("connected", () => {
|
|
384
|
+
console.log("WebSocket connected");
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
lottery.on("error", (err) => {
|
|
388
|
+
console.error("WebSocket error:", err);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
lottery.on("reconnecting", ({ delay }) => {
|
|
392
|
+
console.log(`Reconnecting in ${delay / 1000}s...`);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Start watching
|
|
373
396
|
await lottery.WatchDraw();
|
|
374
397
|
```
|
|
375
398
|
|
|
376
|
-
|
|
399
|
+
**Emitted Events:**
|
|
400
|
+
|
|
401
|
+
| Event | Payload | Description |
|
|
402
|
+
|---|---|---|
|
|
403
|
+
| `draw` | `{ winningTicketNumber: Number, signature: String }` | Fired when a lottery draw is finalized on-chain. |
|
|
404
|
+
| `connected` | — | Fired when the WebSocket connection is established. |
|
|
405
|
+
| `error` | `Error` | Fired when the WebSocket encounters a connection error. |
|
|
406
|
+
| `reconnecting` | `{ delay: Number }` | Fired before an automatic reconnection attempt. `delay` is in milliseconds. |
|
|
377
407
|
|
|
378
408
|
---
|
|
379
409
|
|
package/package.json
CHANGED
package/solotto.d.ts
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
declare module "solotto" {
|
|
2
|
+
import { Connection, PublicKey, Keypair, TransactionInstruction, VersionedTransaction } from "@solana/web3.js";
|
|
3
|
+
import { EventEmitter } from "events";
|
|
4
|
+
|
|
5
|
+
// ── Shared Types ──────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
type PriorityLevel = "Low" | "Medium" | "High" | "VeryHigh" | "Extreme";
|
|
8
|
+
|
|
9
|
+
interface TxParams {
|
|
10
|
+
/** Payer public key as a base-58 string. */
|
|
11
|
+
account: string;
|
|
12
|
+
/** Array of transaction instructions. */
|
|
13
|
+
instructions: TransactionInstruction[];
|
|
14
|
+
/** Keypairs to pre-sign the transaction, or `false`. */
|
|
15
|
+
signers?: Keypair[] | false;
|
|
16
|
+
/** Priority fee level. Defaults to `"Low"`. */
|
|
17
|
+
priority?: PriorityLevel;
|
|
18
|
+
/** Compute unit safety multiplier. Defaults to `1.1`. */
|
|
19
|
+
tolerance?: number | false;
|
|
20
|
+
/** If `true`, serialize the transaction to a `Uint8Array`. */
|
|
21
|
+
serialize?: boolean;
|
|
22
|
+
/** If `true`, base64-encode the serialized transaction. */
|
|
23
|
+
encode?: boolean;
|
|
24
|
+
/** If `true`, simulate and optimise compute units. Defaults to `true`. */
|
|
25
|
+
compute?: boolean;
|
|
26
|
+
/** If `true`, estimate and set priority fees. Defaults to `true`. */
|
|
27
|
+
fees?: boolean;
|
|
28
|
+
/** Address Lookup Table account, or `false`. */
|
|
29
|
+
table?: any | false;
|
|
30
|
+
/** Optional memo string, or `false`. */
|
|
31
|
+
memo?: string | false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface TxResult {
|
|
35
|
+
status: "ok" | "error";
|
|
36
|
+
message: string;
|
|
37
|
+
transaction?: VersionedTransaction | Uint8Array | string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface SimulationError {
|
|
41
|
+
status: "error";
|
|
42
|
+
message: string;
|
|
43
|
+
details?: any;
|
|
44
|
+
logs?: string[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface SendError {
|
|
48
|
+
status: "error";
|
|
49
|
+
message: any;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ── Lottery State ─────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
interface LotteryState {
|
|
55
|
+
/** Lottery authority public key. */
|
|
56
|
+
authority: string;
|
|
57
|
+
/** Lottery numeric identifier. */
|
|
58
|
+
lotteryId: number;
|
|
59
|
+
/** Ticket price in lamports. */
|
|
60
|
+
ticketPrice: number;
|
|
61
|
+
/** Total number of tickets sold. */
|
|
62
|
+
totalTickets: number;
|
|
63
|
+
/** Winning ticket number, or `0`/`null` if not yet drawn. */
|
|
64
|
+
winnerTicketNumber: number | null;
|
|
65
|
+
/** Winner's public key, or `null` if not yet drawn. */
|
|
66
|
+
winnerAddress: string | null;
|
|
67
|
+
/** Whether the lottery is currently active. */
|
|
68
|
+
isActive: boolean;
|
|
69
|
+
/** Prize pool balance in lamports (net of fees when `fees` param is `true`). */
|
|
70
|
+
prizePoolBalance: number;
|
|
71
|
+
/** Whether a draw has been initiated. */
|
|
72
|
+
drawInitiated: boolean;
|
|
73
|
+
/** Prize pool PDA as a base-58 string. */
|
|
74
|
+
prizePoolAddress: string;
|
|
75
|
+
/** Lottery PDA as a base-58 string. */
|
|
76
|
+
lotteryAddress: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ── Ticket State ──────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
interface TicketInfo {
|
|
82
|
+
/** Ticket owner public key. */
|
|
83
|
+
ticketOwner: string;
|
|
84
|
+
/** Ticket receipt account public key. */
|
|
85
|
+
ticketReceipt: string;
|
|
86
|
+
/** The ticket number. */
|
|
87
|
+
ticketNumber: number;
|
|
88
|
+
/** Ticket PDA as a base-58 string. */
|
|
89
|
+
ticketPda: string;
|
|
90
|
+
/** Lottery numeric identifier. */
|
|
91
|
+
lotteryId: number;
|
|
92
|
+
/** Lottery PDA as a base-58 string. */
|
|
93
|
+
lotteryAddress: string;
|
|
94
|
+
/** Lottery authority public key. */
|
|
95
|
+
lotteryAuth: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
interface TicketListItem {
|
|
99
|
+
owner: string;
|
|
100
|
+
lottery: string;
|
|
101
|
+
ticketReceipt: string;
|
|
102
|
+
ticketNumber: number;
|
|
103
|
+
ticketPda: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface TicketListResult {
|
|
107
|
+
lotteryId: number;
|
|
108
|
+
lotteryAddress: string;
|
|
109
|
+
lotteryAuth: string;
|
|
110
|
+
/** The buyer's public key, or `"All"` if unfiltered. */
|
|
111
|
+
buyer: string;
|
|
112
|
+
/** Tickets sorted descending by ticket number. */
|
|
113
|
+
tickets: TicketListItem[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── WatchDraw Events ──────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
interface DrawEvent {
|
|
119
|
+
/** The winning ticket number. */
|
|
120
|
+
winningTicketNumber: number;
|
|
121
|
+
/** The on-chain transaction signature. */
|
|
122
|
+
signature: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface ReconnectingEvent {
|
|
126
|
+
/** Delay in milliseconds before the next reconnection attempt. */
|
|
127
|
+
delay: number;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface LotteryEvents {
|
|
131
|
+
draw: (event: DrawEvent) => void;
|
|
132
|
+
connected: () => void;
|
|
133
|
+
error: (err: any) => void;
|
|
134
|
+
reconnecting: (event: ReconnectingEvent) => void;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ── Authority-like objects ────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
/** An object with at least a `publicKey` property (e.g. a Keypair without the secret key). */
|
|
140
|
+
interface HasPublicKey {
|
|
141
|
+
publicKey: PublicKey;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── Classes ───────────────────────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Low-level transaction builder, sender, and confirmation poller.
|
|
148
|
+
*/
|
|
149
|
+
export class LotteryNetwork {
|
|
150
|
+
connection: Connection;
|
|
151
|
+
|
|
152
|
+
constructor(connection: Connection);
|
|
153
|
+
|
|
154
|
+
/** Build a versioned transaction with automatic compute and fee estimation. */
|
|
155
|
+
Tx(params: TxParams): Promise<TxResult | SimulationError>;
|
|
156
|
+
|
|
157
|
+
/** Send a signed transaction to the network. */
|
|
158
|
+
Send(tx: VersionedTransaction): Promise<string | SendError>;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Poll for transaction confirmation.
|
|
162
|
+
* @param sig - Transaction signature.
|
|
163
|
+
* @param max - Maximum polling attempts (default `10`).
|
|
164
|
+
* @param int - Seconds between polls (default `3`).
|
|
165
|
+
*/
|
|
166
|
+
Status(sig: string, max?: number, int?: number): Promise<string>;
|
|
167
|
+
|
|
168
|
+
/** Simulate a transaction and return the optimised compute unit limit. */
|
|
169
|
+
Compute(
|
|
170
|
+
payer: PublicKey,
|
|
171
|
+
ix: TransactionInstruction[],
|
|
172
|
+
tolerance: number,
|
|
173
|
+
blockhash: string,
|
|
174
|
+
table?: any[] | false
|
|
175
|
+
): Promise<number | SimulationError>;
|
|
176
|
+
|
|
177
|
+
/** Estimate priority fees for a transaction. */
|
|
178
|
+
Estimate(
|
|
179
|
+
payer: HasPublicKey,
|
|
180
|
+
priority_level: PriorityLevel,
|
|
181
|
+
instructions: TransactionInstruction[],
|
|
182
|
+
blockhash: string,
|
|
183
|
+
table?: any[] | false
|
|
184
|
+
): Promise<number>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Player and read operations — buy tickets, claim prizes, query state,
|
|
189
|
+
* and watch draws via WebSocket. Extends `EventEmitter`.
|
|
190
|
+
*/
|
|
191
|
+
export class Lottery extends EventEmitter {
|
|
192
|
+
connection: Connection;
|
|
193
|
+
wss: string | false;
|
|
194
|
+
program: PublicKey;
|
|
195
|
+
|
|
196
|
+
constructor(connection: Connection, wss: string | false, program: PublicKey);
|
|
197
|
+
|
|
198
|
+
// ── Event emitter overrides for type-safe listeners ──
|
|
199
|
+
|
|
200
|
+
on<K extends keyof LotteryEvents>(event: K, listener: LotteryEvents[K]): this;
|
|
201
|
+
once<K extends keyof LotteryEvents>(event: K, listener: LotteryEvents[K]): this;
|
|
202
|
+
off<K extends keyof LotteryEvents>(event: K, listener: LotteryEvents[K]): this;
|
|
203
|
+
emit<K extends keyof LotteryEvents>(event: K, ...args: Parameters<LotteryEvents[K]>): boolean;
|
|
204
|
+
|
|
205
|
+
/** Start a WebSocket subscription for real-time draw events. Auto-reconnects on failure. */
|
|
206
|
+
WatchDraw(): Promise<void>;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Buy one or more tickets.
|
|
210
|
+
* @param buyer - The ticket buyer's keypair.
|
|
211
|
+
* @param authority - The lottery authority (only `publicKey` required).
|
|
212
|
+
* @param lotteryId - Lottery numeric identifier.
|
|
213
|
+
* @param amount - Number of tickets to buy (1–4, default `1`).
|
|
214
|
+
* @param encoded - If `true`, return a base64-encoded transaction.
|
|
215
|
+
*/
|
|
216
|
+
BuyTickets(
|
|
217
|
+
buyer: Keypair,
|
|
218
|
+
authority: HasPublicKey,
|
|
219
|
+
lotteryId: number,
|
|
220
|
+
amount?: number,
|
|
221
|
+
encoded?: boolean
|
|
222
|
+
): Promise<string | TxResult>;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Claim the prize for the winning ticket.
|
|
226
|
+
* @param authority - The lottery authority (only `publicKey` required).
|
|
227
|
+
* @param lotteryId - Lottery numeric identifier.
|
|
228
|
+
* @param winner - The winning ticket owner's keypair.
|
|
229
|
+
* @param encoded - If `true`, return a base64-encoded transaction.
|
|
230
|
+
*/
|
|
231
|
+
ClaimTicket(
|
|
232
|
+
authority: HasPublicKey,
|
|
233
|
+
lotteryId: number,
|
|
234
|
+
winner: Keypair,
|
|
235
|
+
encoded?: boolean
|
|
236
|
+
): Promise<string | TxResult>;
|
|
237
|
+
|
|
238
|
+
/** Fetch the on-chain state of a lottery. */
|
|
239
|
+
GetLottery(
|
|
240
|
+
authority: HasPublicKey,
|
|
241
|
+
lotteryId: number,
|
|
242
|
+
fees?: boolean
|
|
243
|
+
): Promise<LotteryState>;
|
|
244
|
+
|
|
245
|
+
/** Fetch a single ticket by its ticket number. */
|
|
246
|
+
GetTicket(
|
|
247
|
+
authority: HasPublicKey,
|
|
248
|
+
lotteryId: number,
|
|
249
|
+
ticket: number
|
|
250
|
+
): Promise<TicketInfo>;
|
|
251
|
+
|
|
252
|
+
/** Fetch all tickets for a lottery, optionally filtered by buyer. */
|
|
253
|
+
GetTickets(
|
|
254
|
+
authority: HasPublicKey,
|
|
255
|
+
lotteryId: number,
|
|
256
|
+
buyer?: HasPublicKey | false
|
|
257
|
+
): Promise<TicketListResult>;
|
|
258
|
+
|
|
259
|
+
/** Derive the lottery PDA. */
|
|
260
|
+
DeriveLotteryPDA(
|
|
261
|
+
authority: PublicKey,
|
|
262
|
+
lotteryId: number
|
|
263
|
+
): Promise<[PublicKey, number]>;
|
|
264
|
+
|
|
265
|
+
/** Derive a ticket PDA. */
|
|
266
|
+
DeriveTicketPDA(
|
|
267
|
+
lotteryPDA: PublicKey,
|
|
268
|
+
buyer: PublicKey,
|
|
269
|
+
ticketReceipt: PublicKey
|
|
270
|
+
): Promise<[PublicKey, number]>;
|
|
271
|
+
|
|
272
|
+
/** Derive the prize pool PDA. */
|
|
273
|
+
DerivePrizePoolPDA(): Promise<[PublicKey, number]>;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Admin operations — initialize lotteries, trigger draws, lock/unlock ticket sales.
|
|
278
|
+
*/
|
|
279
|
+
export class LotteryManager {
|
|
280
|
+
connection: Connection;
|
|
281
|
+
program: PublicKey;
|
|
282
|
+
|
|
283
|
+
constructor(connection: Connection, program: PublicKey);
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Create a new on-chain lottery.
|
|
287
|
+
* @param authority - The authority keypair that will own the lottery.
|
|
288
|
+
* @param ticketPrice - Ticket price in lamports.
|
|
289
|
+
* @param lotteryId - A unique numeric lottery identifier.
|
|
290
|
+
* @param encoded - If `true`, return a base64-encoded transaction.
|
|
291
|
+
*/
|
|
292
|
+
Initialize(
|
|
293
|
+
authority: Keypair,
|
|
294
|
+
ticketPrice: number,
|
|
295
|
+
lotteryId: number,
|
|
296
|
+
encoded?: boolean
|
|
297
|
+
): Promise<string | TxResult>;
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Trigger the on-chain random draw to select a winner.
|
|
301
|
+
* @param authority - The lottery authority keypair.
|
|
302
|
+
* @param lotteryId - Lottery numeric identifier.
|
|
303
|
+
* @param encoded - If `true`, return a base64-encoded transaction.
|
|
304
|
+
*/
|
|
305
|
+
RandomDraw(
|
|
306
|
+
authority: Keypair,
|
|
307
|
+
lotteryId: number,
|
|
308
|
+
encoded?: boolean
|
|
309
|
+
): Promise<LotteryState | string | TxResult | undefined>;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Lock or unlock ticket sales.
|
|
313
|
+
* @param authority - The lottery authority keypair.
|
|
314
|
+
* @param lotteryId - Lottery numeric identifier.
|
|
315
|
+
* @param lockState - `0` to lock (stop sales), `1` to unlock.
|
|
316
|
+
* @param encoded - If `true`, return a base64-encoded transaction.
|
|
317
|
+
*/
|
|
318
|
+
LockLottery(
|
|
319
|
+
authority: Keypair,
|
|
320
|
+
lotteryId: number,
|
|
321
|
+
lockState: 0 | 1,
|
|
322
|
+
encoded?: boolean
|
|
323
|
+
): Promise<LotteryState | string | TxResult | undefined>;
|
|
324
|
+
}
|
|
325
|
+
}
|
package/solotto.js
CHANGED
|
@@ -162,7 +162,7 @@ class LotteryNetwork {
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
class Lottery {
|
|
165
|
+
class Lottery extends EventEmitter {
|
|
166
166
|
|
|
167
167
|
/***
|
|
168
168
|
* @param {Connection} connection - Solana connection
|
|
@@ -170,6 +170,7 @@ class Lottery {
|
|
|
170
170
|
* @param {PublicKey} program - Lottery Program Id
|
|
171
171
|
*/
|
|
172
172
|
constructor(connection, wss = false, program){
|
|
173
|
+
super();
|
|
173
174
|
this.connection=connection;
|
|
174
175
|
this.wss=wss;
|
|
175
176
|
this.program=program;
|
|
@@ -190,8 +191,6 @@ class Lottery {
|
|
|
190
191
|
async function connect() {
|
|
191
192
|
try{
|
|
192
193
|
console.log('WatchDraw: Connecting to websocket...');
|
|
193
|
-
new EventEmitter();
|
|
194
|
-
EventEmitter.defaultMaxListeners = 1;
|
|
195
194
|
const abortController = new AbortController();
|
|
196
195
|
const subscriptions = createSolanaRpcSubscriptions(self.wss, {intervalMs: 30000});
|
|
197
196
|
const allNotifications = await subscriptions.logsNotifications(
|
|
@@ -204,6 +203,7 @@ class Lottery {
|
|
|
204
203
|
).subscribe({abortSignal:abortController.signal});
|
|
205
204
|
|
|
206
205
|
console.log('WatchDraw: Connected successfully');
|
|
206
|
+
self.emit('connected');
|
|
207
207
|
|
|
208
208
|
for await (const noti of allNotifications) {
|
|
209
209
|
const signature = noti.value.signature;
|
|
@@ -221,18 +221,15 @@ class Lottery {
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
if(isDraw){
|
|
224
|
-
|
|
225
|
-
stopTicketInput.value = winningTicketNumber;
|
|
226
|
-
const spinBtn = document.getElementById('spin-btn');
|
|
227
|
-
const copySignatureBtn = document.getElementById('copy-signature-btn');
|
|
228
|
-
copySignatureBtn.innerHTML = signature;
|
|
229
|
-
spinBtn.click();
|
|
224
|
+
self.emit('draw', { winningTicketNumber, signature });
|
|
230
225
|
}
|
|
231
226
|
}
|
|
232
227
|
}
|
|
233
228
|
catch(err){
|
|
234
229
|
console.log('WatchDraw: Connection error:', err);
|
|
230
|
+
self.emit('error', err);
|
|
235
231
|
console.log(`WatchDraw: Reconnecting in ${RECONNECT_DELAY/1000} seconds...`);
|
|
232
|
+
self.emit('reconnecting', { delay: RECONNECT_DELAY });
|
|
236
233
|
setTimeout(() => {
|
|
237
234
|
connect();
|
|
238
235
|
}, RECONNECT_DELAY);
|