Blockchain lottery smart contract development with Chainlink VRF

If the outcome of a draw cannot be proven, trust in it is lost, and participant claims damage reputation. We develop lottery smart contracts with verifiable randomness end to end: from logic design to handing over documentation to your team. The result is a draw that can be publicly verified, with no manual intervention.

Blockchain Development Services

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1375
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1349
  • B2B Advance company logo design
    B2B Advance company logo design
    794
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1087
  • AIDER company logo development
    AIDER company logo development
    1032
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1129

Smart contract development: where a fair draw breaks

A lottery contract executes where every node must arrive at the same result. That means a source of randomness inside the contract itself is derivable: the input data is visible in advance, and the number can be calculated for the desired bet.

A predictable random number generator based on a block hash or timestamp opens the last-reveal attack — the one who bets last leaves only the option that benefits them.

The cost of such a mistake is broader than a rigged jackpot. Contesting lottery results becomes the norm: participants demand to be shown where the number came from, while the team calculates the winning combination manually and publishes tables.

Manual recalculation destroys what people play the lottery for — the impossibility of influencing the outcome.

Lottery smart contract development begins with moving randomness outside the chain. A lottery smart contract requests a value from an external oracle, which returns it together with a cryptographic proof, and the contract verifies the proof before payouts.

The response cannot be substituted: the verification will not match, and the transaction will revert. We use randomness services where the proof is verified on the contract side, not taken on trust.

The second circuit is a prior commitment: the randomness request is recorded in the log before ticket sales start and revealed after they close. No one knows the outcome at the moment they decide to play.

The prize pool is held in escrow, the calculation of the winning combination is reproducible, and the result is written to the event log.

Therefore, a fair draw is a set of checks that the participant reproduces themselves, not the organizer's promise. Below is how it is structured and where it most often breaks.

What verifiable randomness provides: a measurable effect

Randomness in a lottery is the place where trust breaks instantly: while the number appears in server logs, the participant cannot be sure that the winning number was not rigged.

Verifiable randomness removes the question itself — the number is generated by an external source Chainlink VRF and returned together with a proof that the participant verifies against on-chain records.

What this provides in measurable quantities:

  • Draw transparency. The result and proof are publicly available, so the share of contested draws drops almost to zero — there is nothing to dispute.
  • Fewer support requests. The participant answers the questions «why did this number come up» and «how did you calculate it» themselves, and the support load drops severalfold.
  • Automated prize payouts. The transfer triggers according to the contract condition: the share of manual operations in the cycle is reduced to zero, and the delay between the result and payout is minutes instead of days.
  • Result audit. The draw is reconstructed from the chain of records: who launched it, what number was received, where it went; verification takes minutes instead of reconciling exports.
  • Eliminated failure class. External substitution of the result, a discrepancy between the data and the actual payout, and a «stuck» prize for an inactive participant — these scenarios no longer exist.

Each effect is measurable: the share of contested draws, the number of requests per draw, the share of payouts without human involvement, and the time to verify one result.

We measure these indicators before implementation and after — so that the value is visible in numbers, not in words.

Ways to obtain randomness: comparison of options

A smart contract is deterministic: every network node must obtain the same result, so there is no source of entropy inside the code itself.

Everything taken from the network state — block hash, timestamp, sender address — is known to the one who assembles the block, and they can select the input so that the draw outcome is favorable.

Therefore, there are exactly three options, and they differ not in the «quality of randomness» but in the trust model.

Option How it works When it fits Limitations of the approach
Internal generator Hash of block data or participant address Test networks, internal draws without external betting The outcome is predictable and controllable at the block assembly stage; the participant sees the result before reveal
External randomness source A random number oracle sends the value together with a proof, and the contract verifies it Public lotteries where the outcome must be disputably independent Dependence on oracle availability, a pause between request and response, and network resource consumption for verification
Hybrid draw scheme A commit-reveal scheme from participants plus a final bit from an external source Large pools, a requirement for auditability of every step The most complex contract and the longest audit, more actions required from the participant

Let's name one such provider: Chainlink VRF returns a number with a cryptographic proof, the contract verifies it in the network itself, and only then reveals the winner — a repeated request for the same identifier does not produce a different value.

The hybrid adds protection against collusion: until participants have committed their contributions, rigging the final bit is pointless, while the external source covers the case when all contributions are collected but there is not enough entropy.

The choice does not boil down to «connect an oracle everywhere». If the prize is insignificant and the operator and player roles are separated, an internal generator with an open algorithm is easier to maintain and does not create points of failure.

For a public draw, the limitations of the internal approach outweigh the benefits, and we include an external source or a hybrid — with an explicit description of what will happen if the oracle is unavailable and how the bet refund will proceed.

Smart contract development: stages of engineering work

Lottery mechanics tolerate ambiguity poorly: ambiguity in the rules at the design stage turns into a payout dispute or a halted draw.

Therefore, the route goes from parsing the rules to handing over the contract together with regulations, and each stage ends with an artifact that can be verified.

  1. Audit of the draw mechanics. We parse the rules as a specification: how a ticket is formed, how many winners are in a draw, what happens if there are too few participants or a cancellation. The output is a table of outcomes with an unambiguous contract reaction for each.
  2. Role and payout scheme. We fix who controls what: launching a draw, replenishing the prize reserve, withdrawing commission. The prize payout scheme describes whether funds go directly to the winner, from the common reserve, or via deferred receipt, and what checks are in place on each path.
  3. Assembly and internal tests. We write the contract according to the approved outcome table, cover the branches with tests, and separately cover edge cases: an empty draw, a repeated randomness request, an attempted payout from someone else's address.
  4. Connecting the randomness source. We connect the randomness source via Chainlink VRF: the contract requests a value, waits for confirmation, and behaves correctly during a delay or failure — the draw does not hang and does not produce a predictable result.
  5. Contract acceptance checks. We run the full cycle on a test network: ticket registration, draw, payout, draw cancellation, pause. We close discrepancies with the outcome table before deployment to the main network.
  6. Handover and regulations. We provide contract addresses, the role scheme, access, and instructions: how to launch a draw, what to do if the randomness source fails, and how to prepare a mechanics update. The regulation is part of the result, not an appendix to it.

Schemes, configurations, and regulations: the handover package

The handover package is what your team is left with after delivery. Without it, the draw mechanics live in chat, and any change again requires us. We assemble the artifacts so that the auditor, your engineer, and support read the same documents instead of asking each other again.

  • Smart contract documentation: how the participant list is formed, when a random number is requested from the oracle, what happens on response timeout, which branches lead to payout, and which lead to bet refund.
  • Access role scheme: who launches a round, changes the commission, withdraws funds, and stops the contract; what is protected by multisig, what by the operator role, and what remains inaccessible after rights are handed over.
  • Environment configurations: test and production network parameters, deployed contract addresses, bet limits, and participant counts — in a form ready to reproduce.
  • Incident response regulation: a «symptom — cause — action» matrix for oracle response delay, payout failure, and balance discrepancy, with a division: what the on-call person does and what the owner decides.
  • Support instructions: scenarios for typical requests — payout did not arrive, round hung, bet not displayed — with ready-made wording and escalation points.
  • Version log and rollback: which builds are deployed, how they differ, how to switch the client side to the previous one, and what happens to rounds already started.

We put everything into a repository next to the code and go through it on a call with your engineers and support — the handover should work as a process, not as a folder of files.

From practice: a draw with verifiable randomness before and after

Lottery mechanics ran on a contract where the winner was determined by the hash of the block that closed bet acceptance. Formally fair, in practice a predictability window: the one who forms the block could influence the outcome, and players saw it.

Every contested draw was investigated manually, and trust rested on the operator's reputation, not on verifiable proof.

What broke the mechanics

Randomness was taken from data available before the block was finalized, so in a narrow window the result was predictable. Manual recalculation did not remove the problem: the participant could not verify that the operator had not rigged the outcome.

The share of draws with an open dispute reached several percent, and each investigation cost hours of reconciliation and support.

What was changed and what happened

The contract was moved to an external source of verifiable randomness Chainlink VRF: the number arrives together with a cryptographic proof, and the contract verifies it on the spot. The response cannot be substituted, and the result is visible to participants before payout.

Additionally, reentrancy was closed — the draw executes once per draw, and a repeated call is rejected.

After the rework, contested draws dropped to zero, and manual recalculations were eliminated entirely. The time from closing bets to payout decreased from hours to minutes — it had been held up by manual confirmation and reconciliation.

The share of «prove you didn't rig it» requests became single. Proof verification lies on the protocol side, not in custom code, so auditing this part is faster — we transfer this same circuit to other mechanics with draws.

How does external randomness differ from an internal generator?

An internal generator takes entropy from the block data itself: timestamp, previous block hash, sender address.

From the outside, the value looks random, but all input data is known before the transaction is included in a block — a participant with the right to assemble blocks recalculates the result and discards the unfavorable option. For a lottery, this is a ready-made advantage over other players.

A scheme with an external oracle, such as Chainlink VRF, works differently: the provider publishes a commitment, and after the request is included in a block, it reveals the number and proof of correctness. The contract verifies the proof and accepts the result — the number cannot be peeked at in advance.

Approach Predictability Speed Dependency Maintenance
Block data high: input data is visible in advance in the same transaction none minimal
Player commit-reveal medium: collusion or refusal to reveal player pace, timeout none timeouts, penalties
External oracle low: the number is revealed after the block one or two blocks provider channel monitoring, limits

The price of external randomness is delay and dependence on the provider: the response arrives after one or two blocks, and the channel must be monitored. The internal generator responds in the same transaction but provides no guarantees.

In smart contract development, we fix who changes the draw parameters and at what point, and we design behavior for provider unavailability: a repeated request, postponing the draw, or refunding bets. The circuit is run on a test network before deployment to the main network.

Common technical doubts before starting

Doubts at the evaluation stage concern not the technology but guarantees: who can influence the outcome, what will happen if the external source fails, and whether an already launched contract can be modified. We answer directly — without general formulations.

Can any of the organizers influence the result?

No. The number used to determine the winner comes from an independent provider and is written to the blockchain before the lottery uses it. The organizer cannot substitute the value or cancel the draw after seeing the result.

What should be done if the randomness provider fails?

The request can be repeated: if the value does not arrive on time, the draw is not conducted using an unconfirmed number. The provider itself can be replaced — its logic is moved to a separate module and updated without rebuilding the lottery core.

How can the fairness of the draw be verified after it takes place?

All requests and received values remain in the public blockchain history with a link to the transaction. The auditor checks the chain: the request was sent, the value was received, and the winner was determined according to the stated rule. Access to your servers is not needed for this.

Who is responsible if the external source does fail?

Its operator is responsible for service availability, and our code is responsible for correct failure handling. We run failure scenarios on a test network before launch and record in the agreement how responsibility zones are divided.

We already have a contract deployed — will it have to be rewritten?

Not necessarily. First we look at what is already on-chain: it is often enough to add a randomness-receiving module and update payouts while preserving the history and participant addresses.

If the contract does not support upgrades, we migrate the logic while preserving data — we agree on the plan before making changes.

Let's discuss the task: where to start and what will be needed

To come back with an estimate and work plan, rather than general questions, we need a minimum of input data. They determine the structure of the contracts, the scope of checks, and the order of work — guessing here is more expensive than clarifying.

  • Draw rules: who participates, how the winner is determined, how many prize places there are, and how payouts are distributed.
  • Ticket acceptance mechanics: purchase, subscription, or token holding; how participant weight is calculated and when the pool closes.
  • Randomness source: whether an external verifiable randomness oracle fits or a delayed revealable seed is needed — this determines protection against result rigging.
  • Token and network: what the pool is collected in, mainnet or testnet, and who owns the keys and the contract address.
  • Roles and access: who can pause the draw, change parameters, and withdraw the remainder; whether an admin action log is needed.
  • Restrictions by participant region and age: which checks must be at the entrance and which — outside the contract.
  • Reporting requirements: whether draw exports and a verifiable result history are needed for participants and auditors.

Then we proceed in order: we fix the mechanics in words, agree on the contract scheme, assemble a draw prototype on a test network, test failure scenarios, and only after that deploy to the main network.

Describe the draw mechanics in free form — we will discuss the task, go through contentious points, and come back with an estimate and plan.