Offener Algorithmus

So lost ScopliDrop Gewinner aus,
und warum du es nachprüfen kannst

Unser offengelegter Algorithmus sorgt für eine komplett faire Auslosung. Mehr Lose = bessere Chancen, aber jede teilnehmende Person hat eine echte Chance zu gewinnen. Keine Manipulation, keine Bevorzugung, keine Ausnahmen.

Unser Transparenz-Versprechen

Vertrauen entsteht durch Transparenz. Jeder Schritt unserer Auslosung ist offen einsehbar. Keine Blackbox, keine versteckten Algorithmen, keine geheimen Parameter. Was du siehst, ist genau das, was passiert.

Der Algorithmus hinter der Auslosung

Jeder Gewinner wird von diesem Code ausgelost, direkt aus unserer Codebasis. Kryptografisch sicherer Zufall, keine versteckten Funktionen, keine geheimen Parameter.

WinnerSelection.ts
1// src/lib/services/WinnerSelection.ts
2import { randomInt } from 'crypto';
3import { GiveawayEntry } from '@/components/dashboard/giveaways/types';
4
5/**
6 * Select winners using weighted random selection
7 * @param entries Array of giveaway entries with user IDs and entry counts
8 * @param winnerCount Number of winners to select
9 * @param hasFraudDetection Whether the server has fraud detection enabled (premium+)
10 * @param cooldownExcludedUserIds Optional array of user IDs to exclude due to winner cooldown
11 * @param geoExcludedUserIds Optional array of user IDs to exclude due to geo restriction
12 * (warn-mode entrants and block-mode strays that slipped past the submit gate)
13 * @param referralExcludedUserIds Optional array of user IDs to exclude because they are
14 * below the giveaway's Invite-to-Win referral requirement (premium feature)
15 * @returns Array of selected winner user IDs
16 */
17export function selectWinners(
18 entries: GiveawayEntry[],
19 winnerCount: number,
20 hasFraudDetection: boolean = true, // Default to true for backward compatibility
21 cooldownExcludedUserIds: string[] = [], // Users excluded due to recent wins (cooldown)
22 geoExcludedUserIds: string[] = [], // Users excluded due to geo restriction
23 referralExcludedUserIds: string[] = [] // Users below the Invite-to-Win referral requirement
24): string[] {
25 if (!entries || entries.length === 0) {
26 return [];
27 }
28
29 // Create a Set for O(1) lookup of cooldown excluded users
30 const cooldownExcludedSet = new Set(cooldownExcludedUserIds);
31
32 // Filter out:
33 // 1. Red-flagged entries ONLY if server has fraud detection enabled (premium+)
34 // 2. Users on winner cooldown (won from this server recently)
35 // 3. Users whose entry country falls under the giveaway's geo restriction
36 // 4. Users below the giveaway's Invite-to-Win referral requirement
37 let eligibleEntries = hasFraudDetection
38 ? entries.filter(entry => entry.fraud_flag !== 'red')
39 : entries; // Free servers: include all entries (ignore fraud flags)
40
41 // Apply cooldown exclusions (silent exclusion - users can still enter but won't win)
42 if (cooldownExcludedSet.size > 0) {
43 const beforeCount = eligibleEntries.length;
44 eligibleEntries = eligibleEntries.filter(entry => !cooldownExcludedSet.has(entry.user_id));
45 const excluded = beforeCount - eligibleEntries.length;
46 if (excluded > 0) {
47 console.log(`[Winner Selection] Excluded ${excluded} entries due to winner cooldown`);
48 }
49 }
50
51 // Apply geo exclusions (warn mode: entered with disclosure, can't win)
52 const geoExcludedSet = new Set(geoExcludedUserIds);
53 if (geoExcludedSet.size > 0) {
54 const beforeCount = eligibleEntries.length;
55 eligibleEntries = eligibleEntries.filter(entry => !geoExcludedSet.has(entry.user_id));
56 const excluded = beforeCount - eligibleEntries.length;
57 if (excluded > 0) {
58 console.log(`[Winner Selection] Excluded ${excluded} entries due to geo restriction`);
59 }
60 }
61
62 // Apply Invite-to-Win exclusions (entrants below the referral requirement;
63 // participants were told up-front they must invite X friends to be eligible)
64 const referralExcludedSet = new Set(referralExcludedUserIds);
65 if (referralExcludedSet.size > 0) {
66 const beforeCount = eligibleEntries.length;
67 eligibleEntries = eligibleEntries.filter(entry => !referralExcludedSet.has(entry.user_id));
68 const excluded = beforeCount - eligibleEntries.length;
69 if (excluded > 0) {
70 console.log(`[Winner Selection] Excluded ${excluded} entries below the Invite-to-Win referral requirement`);
71 }
72 }
73
74 // If no eligible entries remain (after fraud + cooldown + geo + referral filtering), return empty array
75 if (eligibleEntries.length === 0) {
76 console.warn('[Winner Selection] No eligible entries after filtering (fraud flags + cooldown + geo + referral-requirement exclusions)');
77 return [];
78 }
79
80 // Create weighted pool of entries based on entry count
81 const entryPool: string[] = [];
82
83 for (const entry of eligibleEntries) {
84 // Add user_id to the pool based on their entry count
85 for (let i = 0; i < entry.entries_count; i++) {
86 entryPool.push(entry.user_id);
87 }
88 }
89
90 // Randomly select winners without duplicates
91 const winners: string[] = [];
92 const winnerSet = new Set<string>();
93
94 // Limit winner count to available unique participants (only eligible entries)
95 const uniqueParticipants = new Set(eligibleEntries.map(entry => entry.user_id));
96 const availableWinnerCount = Math.min(winnerCount, uniqueParticipants.size);
97
98 // If there are no entries or the pool is empty, return empty array
99 if (availableWinnerCount === 0 || entryPool.length === 0) {
100 return [];
101 }
102
103 // Select winners
104 while (winners.length < availableWinnerCount && entryPool.length > 0) {
105 // Select a random entry from the pool
106 const randomIndex = randomInt(entryPool.length);
107 const selectedUserId = entryPool[randomIndex];
108
109 // If this user hasn't already been selected as a winner, add them
110 if (!winnerSet.has(selectedUserId)) {
111 winners.push(selectedUserId);
112 winnerSet.add(selectedUserId);
113 }
114
115 // Remove via swap-and-pop (O(1)) instead of splice (O(n)).
116 // Selection is uniform random so order of remaining elements doesn't matter.
117 entryPool[randomIndex] = entryPool[entryPool.length - 1];
118 entryPool.pop();
119 }
120
121 return winners;
122}

Die wichtigsten Schritte

Klicke auf einen Schritt, um seine Umsetzung im Code zu sehen

Zeile 2

Sicherer Zufall

Gewinner werden mit crypto.randomInt von Node ausgelost, einem kryptografisch sicheren Generator. Es gibt keinen Seed, den man vorhersagen könnte, und nichts zu manipulieren, auch nicht für uns.

Zeile 38

Betrugs- und Cooldown-Filter

Vor der Auslosung werden auf Servern mit Betrugserkennung markierte Teilnahmen entfernt, und wer im Gewinner-Cooldown ist, bleibt außen vor. Free-Server behalten jede Teilnahme.

Zeile 86

Gewichteter Pool

Hier beginnt die Fairness. Jede Person kommt einmal pro verdientem Los in den Pool, 5 Lose heißen also 5 Chancen. Proportional, nie garantiert.

Zeile 106

Die Auslosung

Ein zufälliger Index im gewichteten Pool bestimmt jeden Gewinner. Mehr Lose heißen einfach mehr Plätze, und jeder Platz hat exakt dieselbe Chance.

Zeile 110

Kein doppelter Gewinn

Ein Gewinner-Set stellt sicher, dass niemand zweimal gewinnt, und wir losen nie mehr Gewinner aus, als es teilnahmeberechtigte Personen gibt.

So funktioniert die Fairness

Sieh genau, wie unser Algorithmus jeder teilnehmenden Person eine faire Chance gibt, mit besseren Chancen für die, die mehr machen.

1

Lose sammeln

Mitglieder erledigen Aufgaben und verdienen Lose für ihre Aktionen

2

Gewichteter Pool

Jedes Los kommt je nach erledigten Aufgaben in den Auslosungs-Pool

3

Zufällige Auswahl

Kryptografisch sicherer Zufall wählt aus dem gewichteten Pool

4

Kein doppelter Gewinn

Stellt sicher, dass jede Person pro Giveaway nur einmal gewinnen kann

5

Gewinner bestätigen

Die ausgelosten Gewinner werden geprüft und verkündet

Konkretes Beispiel

Alice erledigt 3 Aufgaben, Bob 1 Aufgabe, Charlie 5 Aufgaben. Der Pool enthält insgesamt 9 Lose, mit proportionalen Gewinnchancen.

Alice

3 Lose verdient

33% Chance

Bob

1 Los verdient

11% Chance

Charlie

5 Lose verdient

56% Chance

Der Pool (9 Lose insgesamt)

Jeder Punkt steht für ein Los. Der Gewinner wird zufällig aus allen Losen gezogen.

Schluss mit manipulierten Giveaways

Ein Discord-Giveaway-Bot, der genau zeigt, wie Gewinner ausgelost werden

Das Problem

Die meisten Discord-Giveaway-Bots sind Blackboxen. Selbst wenn der Bot seriös ist und wirklich zufällig auslost, kann deine Community das nicht nachprüfen. Sie sieht den Algorithmus nicht, kann den Ablauf nicht kontrollieren und nicht belegen, dass die Gewinner nicht von Hand ausgesucht wurden.

Ohne Transparenz wirkt jedes Giveaway verdächtig. Deine Mitglieder fragen sich irgendwann, ob es überhaupt fair zugeht. Das Vertrauen stirbt, das Engagement sinkt.

Wir hatten genug davon, Communitys an verlorenem Vertrauen sterben zu sehen

Die Lösung

Nie wieder Engagement verlieren, weil jemand „manipuliertes Giveaway“ ruft. Wenn Mitglieder an der Fairness zweifeln, schick ihnen einfach den Link zu dieser Seite.

Der Giveaway-Bot ScopliDrop garantiert, dass Server-Inhaber Giveaways weder bearbeiten noch Gewinner auswählen können. Punkt.

Es gibt eine Funktion „Giveaway manuell beenden“, aber die startet nur unseren Auslosungs-Algorithmus, sonst nichts. Server-Admins KÖNNEN KEINE Gewinner auswählen, auf keinem Weg. Das ist unser Versprechen.

Fragen zur Fairness

So stellen wir sicher, dass jedes Giveaway transparent, sicher und für alle Teilnehmenden fair ist.

Mach mit bei der fairen Revolution

Bereit für wirklich faire
Giveaways, ab heute?

Tausende Discord-Communitys sind schon auf transparente, nachprüfbare Giveaways umgestiegen. Starte kostenlos und beweise Fairness vom ersten Tag an.