English Русский فارسی العربية Türkçe Español

QuickLotteryTON

قرارداد هوشمند برای یک قرعه‌کشی ساده روی بلاکچین TON

آدرس قرارداد: EQCsihC1Z6fHRsFbz9N3sCHC6sUfvnlz4RbelethC-6Q34y6 کپی شد!

Tonviewer | Verifier

خلاصه

کوییک لاتاری TON یک قرارداد هوشمند ساده روی بلاکچین TON است. شرکت‌کنندگان با ارسال دستور enter و پرداخت ۱ یا چند TON (مقادیر صحیح، بدون اعشار) وارد قرعه‌کشی می‌شوند.

پس از اینکه ۱۰+ نفر وارد شدند و ۲۴ ساعت گذشت، هر شرکت‌کننده‌ای می‌تواند دستور draw را اجرا کند. حدود ۱۰٪ از شرکت‌کنندگان به طور تصادفی انتخاب شده و پاداش بین آنها تقسیم می‌شود.

تمام!

کد منبع را می‌توانید در پایین مشاهده کنید (مشاهده کد).

نحوه ورود

برای ورود به قرعه‌کشی کافی است ۱ TON (یا ۲، ۳، ۴ و ...) به آدرس قرارداد EQCsihC1Z6fHRsFbz9N3sCHC6sUfvnlz4RbelethC-6Q34y6 کپی شد! با کامنت enter ارسال کنید (دقیقاً همین کلمه، بدون فاصله و با حروف کوچک).

پاسخ‌ها

اگر مقداری شامل اعشار ارسال کنید (مثلاً ۱.۰۰۲ TON)، پول شما بازگردانده می‌شود با پیام Can only enter with 1 TON or multiples of 1 TON.

اگر قبلاً در این دور شرکت کرده باشید، پول شما بازگردانده می‌شود با پیام You have already entered this draw.

اگر ورود موفق باشد، پیامی دریافت می‌کنید: Successfully entered the lottery draw with 1 TON!

قرعه‌کشی

در هر دور تنها یک نفر باید قرعه‌کشی را اجرا کند. معمولاً نیازی به این کار نیست و خودکار انجام می‌شود. فقط کافیست وارد شوید و ۲۴ ساعت منتظر نتایج بمانید!

اگر می‌خواهید قرعه‌کشی را انجام دهید، حداقل ۰.۰۵ TON (بسته به تعداد شرکت‌کنندگان، برای هزینه گس کافی) به آدرس قرارداد EQCsihC1Z6fHRsFbz9N3sCHC6sUfvnlz4RbelethC-6Q34y6 کپی شد! با کامنت draw ارسال کنید.

اگر قرعه‌کشی قبلی کمتر از ۲۴ ساعت پیش بوده باشد، پول بازگردانده می‌شود با پیام Cannot draw yet, X seconds remaining until next draw.

اگر کمتر از ۱۰ نفر وارد شده باشند، پول بازگردانده می‌شود با پیام Not enough participants for draw.

در غیر این صورت، حدود ۱۰٪ از شرکت‌کنندگان به طور تصادفی انتخاب و جایزه بین آنها تقسیم می‌شود. ۱٪ کارمزد به عنوان هزینه گس نگه داشته می‌شود.

برنده پیام زیر را همراه با جایزه دریافت می‌کند: Congratulations! You won 10000000000 nanoTON in the lottery draw!

متدها

در Verifier یا TonViewer می‌توانید متدهای خواندن قرارداد را فراخوانی کنید. متدهای موجود:

خروجی به صورت هگز است و باید به ده‌دهی تبدیل شود.

کد منبع

این کد همچنین در TON Verifier قابل بررسی است:

  1. /**
  2. QuickLotteryTON contract
  3. Explorers:
  4. - Tonviewer: https://tonviewer.com/EQCsihC1Z6fHRsFbz9N3sCHC6sUfvnlz4RbelethC-6Q34y6
  5. - Verifier: https://verifier.ton.org/EQCsihC1Z6fHRsFbz9N3sCHC6sUfvnlz4RbelethC-6Q34y6
  6. Usage:
  7. - Enter lottery:
  8. • Send ≥ 1 TON (multiples of 1 TON) with comment "enter".
  9. • Each address may enter once per draw.
  10. - Getters:
  11. • balance() → current contract balance (nanoTON).
  12. • betPool() → total TON in the current lottery pool (nanoTON).
  13. • participantCount() → number of unique participants.
  14. - Draw:
  15. • Anyone can trigger via sending any amount of TON with comment "draw".
  16. • At most once every 24h.
  17. • Requires ≥ 10 participants before allowing draw.
  18. - Payout:
  19. • 1% fee to deployer for transaction fees.
  20. • Remaining pool distributed proportionally among ~10% of participants, chosen randomly.
  21. */
  22. import "@stdlib/deploy";
  23. const NANO_COUNT: Int = 1_000_000_000;
  24. message TransferEvent {
  25. amount: Int as int64;
  26. recipient: Address;
  27. }
  28. message EntryEvent {
  29. sender: Address;
  30. amount: Int as int64;
  31. }
  32. contract QuickLotteryTON with Deployable {
  33. const DRAW_EVERY: Int = 24 * 60 * 60; // Once every day at most.
  34. const MIN_PARTICIPANTS: Int = 10;
  35. lastDrawTime: Int;
  36. participants: map<Address, Int>;
  37. participantCount: Int;
  38. betPool: Int;
  39. deployer: Address;
  40. init() {
  41. nativeReserve(ton("1.0"), ReserveAtMost | ReserveBounceIfActionFail);
  42. self.deployer = sender();
  43. self.participantCount = 0;
  44. self.betPool = 0;
  45. self.participants = emptyMap();
  46. self.lastDrawTime = now();
  47. }
  48. receive("enter") {
  49. let amount: Int = context().value;
  50. if (amount < NANO_COUNT || amount % NANO_COUNT != 0) {
  51. self.reply("Can only enter with 1 TON or multiples of 1 TON.".asComment());
  52. return;
  53. }
  54. let sender: Address = sender();
  55. if (self.participants.exists(sender)) {
  56. self.reply("You have already entered this draw.".asComment());
  57. return;
  58. }
  59. self.participants.set(sender, amount);
  60. self.participantCount += 1;
  61. self.betPool += amount;
  62. // Emit entry event
  63. emit(EntryEvent{sender: sender, amount: amount}.toCell());
  64. // Send confirmation message to participant with bet amount
  65. let sb: StringBuilder = beginString();
  66. sb.append("Successfully entered the lottery draw with ");
  67. sb.append((amount / NANO_COUNT).toString());
  68. sb.append(" TON!");
  69. send(SendParameters{
  70. to: sender,
  71. bounce: false,
  72. value: 0, // No TON refunded
  73. mode: SendIgnoreErrors | SendPayFwdFeesSeparately,
  74. body: sb.toString().asComment()
  75. });
  76. }
  77. receive("draw") {
  78. // Check time since last draw
  79. let remaining: Int = self.DRAW_EVERY - (now() - self.lastDrawTime);
  80. if (remaining > 0) {
  81. let sb: StringBuilder = beginString();
  82. sb.append("Cannot draw yet, ");
  83. sb.append(remaining.toString());
  84. sb.append(" seconds remaining until next draw.");
  85. self.reply(sb.toString().asComment());
  86. return;
  87. }
  88. if (self.participantCount < self.MIN_PARTICIPANTS) {
  89. self.reply("Not enough participants for draw.".asComment());
  90. return;
  91. }
  92. // Send 1% fee to owner
  93. let ownerFee: Int = self.betPool / 100;
  94. if (ownerFee > 0) {
  95. emit(TransferEvent{amount: ownerFee, recipient: self.deployer}.toCell());
  96. send(SendParameters{
  97. to: self.deployer,
  98. bounce: true,
  99. value: ownerFee,
  100. mode: SendIgnoreErrors
  101. });
  102. }
  103. // Determine prize pool and winner count
  104. let pool: Int = self.betPool - ownerFee;
  105. let targetWinners: Int = self.participantCount / 10; // 10% winners
  106. // Select winners
  107. let winners: map<Address, Int> = emptyMap();
  108. let winnerCount: Int = 0;
  109. let totalWinnerWeight: Int = 0;
  110. // First pass: try to select winners with 10% chance
  111. while (winnerCount == 0) {
  112. foreach (adr, winnerWeight in self.participants) {
  113. if (random(1, 100) <= 10 && winnerCount < targetWinners) {
  114. winners.set(adr, winnerWeight);
  115. totalWinnerWeight += winnerWeight;
  116. winnerCount += 1;
  117. }
  118. }
  119. }
  120. // Distribute prizes proportionally to bet amounts
  121. foreach (winnerAddress, winnerWeight in winners) {
  122. let prize: Int = pool * winnerWeight / totalWinnerWeight;
  123. if (prize > 0) {
  124. // Create notification message with prize amount
  125. let sb: StringBuilder = beginString();
  126. sb.append("Congratulations! You won ");
  127. sb.append((prize).toString());
  128. sb.append(" nanoTON in the lottery draw!");
  129. // Emit transfer event
  130. emit(TransferEvent{amount: prize, recipient: winnerAddress}.toCell());
  131. // Send prize with notification message in a single transaction
  132. send(SendParameters{
  133. to: winnerAddress,
  134. bounce: true,
  135. value: prize,
  136. mode: SendIgnoreErrors,
  137. body: sb.toString().asComment()
  138. });
  139. }
  140. }
  141. // Reset lottery
  142. self.participantCount = 0;
  143. self.betPool = 0;
  144. self.participants = emptyMap();
  145. self.lastDrawTime = now();
  146. }
  147. get fun participantCount(): Int {
  148. return self.participantCount;
  149. }
  150. get fun betPool(): Int {
  151. return self.betPool;
  152. }
  153. get fun balance(): Int {
  154. return myBalance();
  155. }
  156. }