Coder Social home page Coder Social logo

aftermath2 / btry Goto Github PK

View Code? Open in Web Editor NEW
3.0 1.0 1.0 729 KB

Accountless lottery powered by the Bitcoin Lightning Network

License: GNU Affero General Public License v3.0

Dockerfile 0.31% Shell 0.17% Go 39.07% HTML 0.20% CSS 2.57% TypeScript 57.61% JavaScript 0.08%
bitcoin lightning-network

btry's Introduction

BTRY

BTRY is an accountless lottery that uses asymmetric cryptography to register bets/prizes, and the Lightning Network to send and receive payments. The lotteries are:

  • Completely private
  • Globally available
  • Permissionless
  • Transparent and auditable
  • Bitcoin only

Onion site: http://22id55jzspf3mo5duk5z4honwhqdl7ebtmkemccknmpkniytxwqzzzyd.onion

Note

BTRY requires a browser proxied through Tor to be accessed. It can't be accessed through clearnet.

Lottery

Users participate for the opportunity of winning the funds that were bet in the same lottery. Each one lasts 144 Bitcoin blocks (~24 hours).

Winning tickets are generated using the bytes of the Bitcoin block hash that was mined at the lottery height target. Any user can generate the winning tickets themselves and verify that the prizes were correctly assigned.

BTRY decodes the hash and iterates the bytes in reverse, it uses two numbers to calculate each winning ticket. The formula used is $(a ^ b)\mod prizePool$.

For example:

blockHash = "000000000000000000003bc0544004a6e74beb66b21b1e564eb81dbd478d67c6"
decodedBlockHashBytes = [0 0 0 0 0 0 0 0 0 0 59 192 84 64 4 166 231 75 235 102 178 27 30 86 78 184 29 189 71 141 103 198]
prizePool = 10,000

firstWinner = (198 ^ 103) % prizePool = 9,392
secondWinner = (141 ^ 71) % prizePool = 5,941
thirdWinner = (189 ^ 29) % prizePool = 4,909
...
eighthWinner = (75 ^ 231) % prizePool = 1,875

Bets

One payment is one bet and the number of sats is the number of tickets the user gets (1 sat = 1 ticket). Bets can be as little as 1 sat and as big as the capacity available.

In this lottery, ticket numbers are not chosen by the user but rather assigned sequentially.

For example, if the first player bets 500,000 sats, it will have tickets from 1 to 500,000 (including the last one). A second user betting 100,000 sats will have tickets from 500,001 to 600,000.

A single ticket can win multiple prizes. All users participate for the 99.609375% of the prize pool.

Prizes

Prizes distribution as a percentage of the prize pool:

Place Prize
1st 50
2nd 25
3rd 12.5
4th 6.25
5th 3.125
6th 1.5625
7th 0.78125
8th 0.390625
BTRY fee 0.390625

Prizes expire after 720 blocks, so make sure to withdraw them within this window. This is to avoid having liquidity locked for long periods of time, which would disable the ability of receiving more bets.

If you would like the prizes to be sent to you automatically, consider linking a lightning address to your private key and BTRY will attempt to pay the winners after they are known. Please note that this may degrade your privacy.

Users can also opt to receive notifications through telegram in case of winning.

Authentication

No account required, just an ed25519 key pair. It can be generated randomly by the client or provided by the user, please make sure to back it up since it's the only way you can withdraw your prizes.

For higher privacy it's suggested not to re-use the same secret on different days.

To generate your own private key you could use this simple command

openssl genpkey -algorithm ed25519 -out private_key.pem
openssl asn1parse -in private_key.pem -offset 14 | tail -c 65

Warning

Do not share your private key. It is never sent to the server, only its derived public key and signature are used to store your bets and claim the prizes in case you win.

Building BTRY

Note

Requires Go 1.21 and Node.js 20+ installed

git clone https://github.com/aftermath2/btry.git
cd btry
./build.sh

Macaroons

BTRY uses several RPC methods to perform operations with a Lightning Node, we suggest creating a fine-grained macaroon for it:

lncli bakemacaroon uri:/lnrpc.Lightning/AddInvoice uri:/lnrpc.Lightning/DecodePayReq uri:/routerrpc.Router/SendPaymentV2 uri:/lnrpc.Lightning/ListChannels uri:/lnrpc.Lightning/SubscribeChannelEvents uri:/lnrpc.Lightning/SubscribeInvoices uri:/routerrpc.Router/TrackPayments

btry's People

Contributors

aftermath2 avatar

Stargazers

 avatar  avatar 22388o⚡️  avatar

Watchers

 avatar

Forkers

22388o

btry's Issues

Battles

Development branch
battles

Description

Battles are a non-custodial PvP game based on HODL contracts where two players compete for a fixed amount of money.

The funds are never in the hands of BTRY, it merely acts as a coordinator and decides which payment to settle (loser -> winner) and which one to cancel (winner -> loser).

Initially, the idea is simple, both users choose one number between 0 and 1000, BTRY generates one randomly and the one that got it closer wins.

However, we may move towards other forms of deciding a winner, like real events outcomes. There has been demand for a sports betting platform based on Lightning on some forums and these technologies may be a great fit for that.

The random number generation is based on provably fair random numbers, so both parties can validate that the results are fair and not manipulated.

Flow

The desired flow for each participant would be the following

Initiator

  1. Createa game selecting the amount (sats)
  2. Select a number between 0 and 1000 and send an invoice for the amount he chose in 1
  3. Wais for a user to join the game and listen for a HODL invoice to determine whether a user joined the game or not
  4. Fund the HODL invoice the service created
  5. Wait for the result and verify the random number

Challenger

  1. Join game
  2. Send a number and an invoice for the amount specified in the game
  3. Fund the HODL invoice
  4. Wait for the result and verify the random number

BTRY

  1. Check if both users chose the same number, in that case, there's a tie and both HODL invoices are cancelled
  2. Pick a random number between 0 and 1000 using provably fair random numbers
  3. Pick winner, settle loser HODL invoice and cancel winner invoice

Details

All battles have a 1h expiration time for another player to join the game.

After the game has finished, the results are saved for the users to verify the numbers.

Provably fair random number generation

Winner number should be generated using provably fair random number generator. For this, we should first generate a random server seed, encrypt it and give it to the players (so they can later verify that the server seed was not modified), get a seed from each of them and calculate

HMAC_SHA256(server_seed, player1_seed, player2_seed, nonce)

Both player's seeds must be shared in the game

Convert the (first) byte/s to number and choose the winner. In the payment description, include the unencrypted server seed and the secret used to encrypt it.

Example

a: server seed
b: client seed
0: nonce

HMAC_SHA256(a,b:0)

First four bytes:
ad 	a0 	97 	d5
173 	160 	151 	213

(173, 160, 151, 213) -> [0, ..., 1000] = 678
	0.675781250000 	(173 / (256 ^ 1 ))
+ 	0.002441406250 	(160 / (256 ^ 2 ))
+ 	0.000009000301 	(151 / (256 ^ 3 ))
+ 	0.000000049593 	(213 / (256 ^ 4 ))
= 	0.678231706144 	(* 1000) -> 1000 is the maximum number the users can choose
= 	678.231706144
=	678

Ideas

  • Support games with more than 2 players.
  • Private battles only joinable by URL.
  • Battles outcome decided by real time events.

Improve FAQ section

Description

The FAQ section of the user interface is hard-coded, which means it can't be translated and that any change in the server's source code could leave it outdated. Moreover, it's plain text and it does not support creating tables, using bold text, links, etc.

This issue aims to investigate ways of removing these limitations.

Block-based lottery duration

Description

Currently there is one lottery every 24 hours starting at 00:00 UTC. However, we could switch to a block-based duration of 144 blocks per lottery and use the 144th block header hash as a source of entropy to generate the winning numbers.

That way, users would be able to prove that the numbers were generated randomly and not arranged or manipulated. Right now, they must trust that the code running in the production server is indeed the one present in this repository's master branch.

Reminder notifications

Description

Given that prizes expire, we should send reminder notifications to users that have notifications enabled and that still haven't withdrawn their funds.

The notification should be sent every day until the funds expire.

Add on-chain support

Description

Although BTRY was originally designed to work with the Lightning Network and relatively small payments, it may eventually be appropriate to let users to bet and, more importantly, withdraw prizes using Bitcoin's first layer.

This would require to have enough on-chain liquidity available to process all withdrawals. Splices may facilitate this process, otherwise we would need a mechanism to loop-out funds or close idle channels automatically.

Once the issue above is solved, we should add support for receiving bets and sending withdrawals via on-chain transactions.

Design

The pages bet and withdraw should have two tabs Lightning and On-chain for the users to switch between layers.

The new on-chain section should have three inputs:

  1. Bitcoin address
  2. Amount in BTC or satoshis
  3. Fee rate in sat/vB (optional)

If specified, the final fee amount should be deducted from the total amount sent. A tooltip should be next to the fee input box title explaining this.

If the fee rate is not set, we should use LND's estimatefee fastest option, with a maximum value of 200.

Automatic withdrawals via lightning addresses

Description

Let the users specify a lightning address to automatically send them the prizes in case they win.

Design

Users should be able to send they address only if they have previously made a bet that day and if the address is valid.

The payments should be attempted right after old prizes have expired:

btry/lottery/lottery.go

Lines 132 to 135 in 8a09e7a

expiredPrizes, err := l.db.Winners.ExpirePrizes()
if err != nil {
return err
}

And may be retried multiple times if they fail, possibly dividing the total prize in smaller payments. A notification should be sent to the user with information about the payments final status, whether the prizes could be sent or not.

Payments should use a default fee of 1500 ppm, which will be deducted from the prizes.

The option to add the lightning address should be in the user's menu. The button's name could be "Enable automatic withdrawal".

Finished lotteries bets visibility

Description

Currently, all bets are deleted from the database after the winners are announced. This prevents the users from viewing the end state of the lottery and verifying that the prizes were assigned correctly. We should link the bets to a lottery_height and keep them after the lottery has ended.

Fix rate limiter unit test

Description

The http\api\middleware\limiter_test.go unit test is failing on Ubuntu but passing on other OSs.

The logic seems correct, but there might be a difference in the funcionality of the httptest.Recorder that is causing it to fail.

// func TestRateLimiter(t *testing.T) {

Replace Telegram with open source and privacy-friendly services

Description

Telegram is closed-source and requires a telephone number to use, there are much better alternatives that could provide the same functionality while preserving the users' privacy like Nostr or SimpleX.

This issue aims to include these platforms to receive winning notifications.

verifiable winner selection

Bringing this over from stacker.news

From a glance at the code, it seems like the winner is chosen by the server completely at random. How is that verifiable?

Specifically this is the function (in lottery/lottery.go) which chooses a winner from a set of bets.

It computes a die roll, weighted by bet size, which seems OK. But the actual entropy for the die roll is pulled from the server's internal RNG. I can't see where the 'provable fairness' or 'auditability' of the winner is derived from. Honest players would have no way of distinguishing an honest win from a colluding win.

It would make more sense to me if the winner was selected by hashing some undisputable but unpredictable future data, like the hash of a yet-to-be-mined block, along with a lottery-specific salt to prevent tampering by miners. You'd want to let the block confirm two or three times before choosing the winner, in case of chain reorgs.

There's also the question of proving the server won't run away with the prizes. Once everyone deposits money into the lottery, what prevents the server from simply not paying out the prizes to the true winners? (maybe that should be a separate issue)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.