Skip to content

Commit e9e04a4

Browse files
authored
Merge pull request #32 from N-010/main
Pulse Proposal
2 parents ab7aa31 + 6aa218c commit e9e04a4

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed

SmartContracts/2026-01-12-Pulse.md

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
# Pulse
2+
3+
## Available Options
4+
> Option 0: no, dont allow
5+
6+
> Option 1: yes, allow
7+
8+
## Table of Contents
9+
1. [Introduction](#1-introduction)
10+
2. [Game Mechanics](#2-game-mechanics)
11+
3. [Auto Participation](#3-auto-participation)
12+
4. [Revenue Distribution](#4-revenue-distribution)
13+
5. [Prize Structure](#5-prize-structure)
14+
6. [Settlement Process](#6-settlement-process)
15+
7. [Admin Controls and Configuration](#7-admin-controls-and-configuration)
16+
8. [Code](#8-code)
17+
18+
---
19+
20+
## 1. Introduction
21+
22+
Pulse is a 6-digit lottery smart contract on Qubic. Each ticket holds six digits
23+
in the range [0, 9]. Winning digits are also six draws from [0, 9], with
24+
duplicates allowed. Payouts use fixed reward tables with a pro-rata fallback
25+
when contract balance is insufficient. The contract enforces a QHeart balance
26+
cap and sweeps excess to the QHeart issuer wallet.
27+
28+
### Key Features
29+
30+
- Fixed prize tables (left-aligned and any-position) with best-of selection
31+
- Scheduled draws (Wednesday always; plus schedule bitmask, default Wed/Fri/Sun at 11:00 UTC)
32+
- Configurable fee split (dev, burn, PULSE shareholders, Random Lottery shareholders, QHeart wallet)
33+
- Pro-rata payouts under insufficient balance
34+
- Auto-participation deposits and auto-purchasing
35+
- QHeart balance cap with excess sweep
36+
37+
---
38+
39+
## 2. Game Mechanics
40+
41+
### Number Selection
42+
43+
- Ticket digits are six values in [0, 9].
44+
- Duplicate digits are allowed.
45+
- Any digit outside [0, 9] is rejected.
46+
47+
### Ticket Purchase
48+
49+
#### BuyTicket
50+
1. Fails if selling is closed.
51+
2. Validates digits are within range.
52+
3. Fails if the round ticket cap (1,024) is reached.
53+
4. Fails if the player does not have sufficient QHeart.
54+
5. Transfers ticket price to the contract and records the ticket.
55+
56+
#### BuyRandomTickets
57+
1. Fails if count is zero.
58+
2. Fails if selling is closed.
59+
3. Clamps purchase count to the remaining slots.
60+
4. Fails if no slots remain.
61+
5. Charges the player for the clamped count.
62+
6. Allocates random digits for each ticket.
63+
64+
### Winning Criteria
65+
66+
For each ticket, the prize is the maximum of:
67+
- **Left-aligned matches**: number of consecutive matches from index 0 until the first mismatch.
68+
- **Any-position matches**: sum over digits of `min(ticketCount[d], winningCount[d])`.
69+
70+
Duplicates count toward matches based on multiplicity.
71+
72+
---
73+
74+
## 3. Auto Participation
75+
76+
### Overview
77+
78+
Users can deposit QHeart for automatic purchases. Each auto entry stores:
79+
- `deposit` (QHeart reserved in the contract wallet)
80+
- `desiredTickets` (number of tickets to buy per auto run)
81+
82+
The contract maintains a registry capped at 512 entries
83+
(half of the ticket capacity).
84+
85+
### DepositAutoParticipation
86+
87+
- Rejects if registry is full (including attempts to top up an existing entry).
88+
- Rejects if `amount <= 0` or `desiredTickets <= 0`.
89+
- Clamps `desiredTickets` to `maxAutoTicketsPerUser` when non-zero.
90+
- Clamps `amount` to available user balance.
91+
- Requires `amount >= ticketPrice * desiredTickets`.
92+
- If `buyNow` and selling is open, buys up to `desiredTickets` via `BuyRandomTickets` (clamped by remaining slots).
93+
- After the buy, the requested `amount` is reduced by `ticketPrice * desiredTickets`.
94+
- If the remainder is `<= 0`, no entry is created.
95+
- Otherwise, the remainder is transferred to the contract and stored/updated.
96+
- If `buyNow` is false or selling is closed, the full `amount` is transferred and stored/updated.
97+
98+
### WithdrawAutoParticipation
99+
100+
- Rejects if no entry exists.
101+
- If `amount <= 0`, withdraws the full deposit.
102+
- Otherwise withdraws `min(amount, deposit)`.
103+
- Removes entry if deposit becomes zero.
104+
105+
### SetAutoConfig
106+
107+
- `desiredTickets < -1` is treated as `-1`.
108+
- `desiredTickets == -1` keeps the existing value.
109+
- `desiredTickets == 0` is invalid.
110+
- `desiredTickets > 0` sets a new value.
111+
112+
### SetAutoLimits
113+
114+
- Owner-only. Sets `maxAutoTicketsPerUser` immediately.
115+
- `0` disables the per-user limit.
116+
- Values above the ticket cap are clamped to 1,024.
117+
- Existing entries are updated to comply with the new limit.
118+
119+
### Auto Purchase Timing
120+
121+
Auto purchases can run:
122+
- At `BEGIN_EPOCH` when selling is open (and not at the bootstrap sentinel).
123+
- At `BEGIN_TICK` on the first valid day after bootstrap to seed selling.
124+
- At `BEGIN_TICK` after a non-Wednesday draw when selling reopens.
125+
126+
Auto purchases are skipped when selling is closed or no slots remain.
127+
Unaffordable entries are removed.
128+
After Wednesday draws, selling remains closed until the next epoch begins.
129+
130+
---
131+
132+
## 4. Revenue Distribution
133+
134+
Ticket revenue is split by configured percentages:
135+
- Dev
136+
- Burn
137+
- PULSE shareholders
138+
- Random Lottery (RL) shareholders
139+
- QHeart wallet
140+
- Remainder retained in the contract for prizes
141+
142+
**Defaults:**
143+
- Dev: 10%
144+
- Burn: 5%
145+
- PULSE shareholders: 8%
146+
- Random Lottery shareholders: 2%
147+
- QHeart wallet: 5%
148+
149+
The sum of percentages (including Random Lottery shareholders) must be <= 100.
150+
151+
Shareholder rewards are distributed pro-rata to holders of the `PULSE` asset and the Random Lottery asset.
152+
153+
---
154+
155+
## 5. Prize Structure
156+
157+
### Left-Aligned Reward Table
158+
159+
| Matches | Reward |
160+
|---------|--------|
161+
| 6 | 2000 x ticket price |
162+
| 5 | 300 x ticket price |
163+
| 4 | 60 x ticket price |
164+
| 3 | 20 x ticket price |
165+
| 2 | 4 x ticket price |
166+
| 1 | 1 x ticket price |
167+
| 0 | 0 |
168+
169+
### Any-Position Reward Table
170+
171+
| Matches | Reward |
172+
|---------|--------|
173+
| 6 | 150 x ticket price |
174+
| 5 | 30 x ticket price |
175+
| 4 | 8 x ticket price |
176+
| 3 | 2 x ticket price |
177+
| 2 | 0 |
178+
| 1 | 0 |
179+
| 0 | 0 |
180+
181+
### Payout Rule
182+
183+
For each ticket:
184+
```
185+
prize = max(leftAlignedReward, anyPositionReward)
186+
```
187+
188+
If the contract balance is insufficient to pay all prizes:
189+
```
190+
scaledPrize = floor(prize * availableBalance / totalPrize)
191+
```
192+
193+
---
194+
195+
## 6. Settlement Process
196+
197+
Settlement is triggered during `BEGIN_TICK` when:
198+
1. Current hour >= draw hour
199+
2. Day is Wednesday, or matches the configured schedule bitmask
200+
3. The date differs from the last draw date
201+
202+
Draw checks are throttled to every 100 ticks.
203+
204+
### Settlement Steps
205+
206+
1. If no tickets sold, return.
207+
2. Compute round revenue: `ticketPrice * ticketCounter`.
208+
3. Transfer fees (dev, burn, PULSE shareholders, Random Lottery shareholders, QHeart wallet).
209+
4. Generate six winning digits from the previous spectrum digest.
210+
5. Compute total prize across all tickets.
211+
6. Pay prizes (full or pro-rata).
212+
7. Update winners ring buffer.
213+
8. Sweep excess balance above `qheartHoldLimit` to the QHeart wallet.
214+
9. Clear tickets and close the round.
215+
10. Reopen selling after non-Wednesday draws and run auto-purchases.
216+
217+
---
218+
219+
## 7. Admin Controls and Configuration
220+
221+
Owner-only procedures use the QHeart issuer as the admin address.
222+
Unless noted, changes are scheduled and applied at `END_EPOCH`:
223+
224+
- `SetPrice(newPrice)` (must be > 0)
225+
- `SetSchedule(newSchedule)` (bitmask, must be non-zero)
226+
- `SetDrawHour(newDrawHour)` (0-23)
227+
- `SetFees(dev, burn, shareholders, rlShareholders, qheart)` (sum <= 100)
228+
- `SetQHeartHoldLimit(newLimit)`
229+
- `SetAutoLimits(maxTicketsPerUser)` (applies immediately)
230+
231+
At `BEGIN_EPOCH`, if the schedule or draw hour is `0`, it resets to the defaults.
232+
233+
Default configuration:
234+
- Ticket price: 200,000 QHeart
235+
- Draw hour: 11:00 UTC
236+
- Schedule: Wednesday, Friday, Sunday
237+
- Hold limit: 2,000,000,000 QHeart
238+
- Auto limit: 512 tickets per user
239+
- Fees: 10% dev, 5% burn, 8% PULSE shareholders, 2% Random Lottery shareholders, 5% QHeart wallet
240+
---
241+
242+
## 8. Code
243+
244+
[PR](https://github.com/qubic/core/pull/714)
245+
246+
---

0 commit comments

Comments
 (0)