Skip to content

Conversation

pingu-73
Copy link
Owner

@pingu-73 pingu-73 commented Jun 28, 2025

Overview

This PR implements a Zero-Collateral Lottery system (2-player lottery only):

  • Commitment scheme with hash-based commitments
  • 2-player match execution with XOR-based winner determination
  • CLI for creating and joining 2-player games

Why?

Traditional online gambling suffers from:

  • Custodial risk: Players must trust operators with their funds
  • High collateral requirements: Security deposits often exceed bet amounts
  • Centralized control: Operators can freeze or confiscate funds

This implementation eliminates these issues through:

  • Self-custodial betting: Players retain control until the moment of betting
  • Zero collateral: No security deposits required beyond the bet amount
  • Cryptographic fairness: Winner determination through verifiable randomness

The zero-collateral lottery paper by Miller et al. demonstrated the theoretical possibility of fair lotteries without security deposits. However, the paper focused on cryptographic protocols without addressing practical value transfer mechanisms. This implementation bridges that gap by:

  • Integrating real Bitcoin transactions through the Ark protocol
  • Providing actual economic incentives for participation
  • Demonstrating deployment of academic cryptographic research
    refer: https://arxiv.org/pdf/1612.05390

Features

Bet Collection & Escrow

  • Dedicated Pot Wallets: Each game creates an isolated wallet for escrow
  • Atomic Bet Placement: Players send actual sats to the pot via Ark transactions
  • Balance Verification: Comprehensive checks ensure sufficient funds before betting
  • Network Compatibility: Full support for Mutinynet, Signet, and Regtest

Pot Management

  • Isolated Fund Storage: Each game's funds are completely separated
  • Automatic Payout System: Winners receive the full pot automatically (NOTE: currently not possible because the pot funds need to be confirmed and in my ark-protocol impl round participation only happens when funds are sent to boarding addr)
  • Refund Mechanisms: Automatic refunds if games are aborted
  • Audit Trail: Complete transaction history for all pot operations

Game State Management

  • Persistent Player-Wallet Mapping: Tracks which wallet belongs to each player
  • State Synchronization: Game state persists correctly across CLI sessions
  • Status Tracking: Comprehensive game status with bet placement tracking

@pingu-73
Copy link
Owner Author

The lottery is simulating the game logic in the following way:

~/Desktop/proposal/testing/arkive-sdk zero-collateral* 2m 23s
❯ coinflip create alice-wallet 1000
Created new game!
Game ID: 667bef7d-d5a5-4912-a941-126cf6d157cd
Your Player ID: d5b52dd8-5173-469d-816a-c913ebb731eb
Bet Amount: 1000 sats
Waiting for second player to join...

Share this command with another player:
coinflip join <their-wallet> 667bef7d-d5a5-4912-a941-126cf6d157cd

~/Desktop/proposal/testing/arkive-sdk zero-collateral*
❯ coinflip join bob-wallet 667bef7d-d5a5-4912-a941-126cf6d157cd
Joined game 667bef7d-d5a5-4912-a941-126cf6d157cd!
Your Player ID: 9fe78bb4-04aa-4762-ade6-5488de51e4aa
Game is now ready!

Both players can now commit:
coinflip commit alice-wallet 667bef7d-d5a5-4912-a941-126cf6d157cd
coinflip commit bob-wallet 667bef7d-d5a5-4912-a941-126cf6d157cd

~/Desktop/proposal/testing/arkive-sdk zero-collateral*
❯ coinflip commit alice-wallet 667bef7d-d5a5-4912-a941-126cf6d157cd && coinflip commit bob-wallet 667bef7d-d5a5-4912-a941-126cf6d157cd
Commitment submitted for game 667bef7d-d5a5-4912-a941-126cf6d157cd!
Your Player ID: d5b52dd8-5173-469d-816a-c913ebb731eb
Your secret (save this for reveal): 2cae18fc4d9fe11e3ad215e2986817fc7efaa4d782c20473d5989b1cf0cdb4e9

Wait for other player to commit...
Commitment submitted for game 667bef7d-d5a5-4912-a941-126cf6d157cd!
Your Player ID: 9fe78bb4-04aa-4762-ade6-5488de51e4aa
Your secret (save this for reveal): 173d67f2a3d7a000deaa52e47e2482ffa790e315701c6d18f4e9c2383cdee700

Both players have committed! Now reveal your commitment:
coinflip reveal bob-wallet 667bef7d-d5a5-4912-a941-126cf6d157cd 173d67f2a3d7a000deaa52e47e2482ffa790e315701c6d18f4e9c2383cdee700

~/Desktop/proposal/testing/arkive-sdk zero-collateral*
❯ coinflip reveal bob-wallet 667bef7d-d5a5-4912-a941-126cf6d157cd 173d67f2a3d7a000deaa52e47e2482ffa790e315701c6d18f4e9c2383cdee700
Commitment revealed for game 667bef7d-d5a5-4912-a941-126cf6d157cd!
Waiting for other player to reveal...

~/Desktop/proposal/testing/arkive-sdk zero-collateral*
❯ coinflip reveal alice-wallet 667bef7d-d5a5-4912-a941-126cf6d157cd 2cae18fc4d9fe11e3ad215e2986817fc7efaa4d782c20473d5989b1cf0cdb4e9
Commitment revealed for game 667bef7d-d5a5-4912-a941-126cf6d157cd!

======GAME COMPLETED!======
Winner: 9fe78bb4-04aa-4762-ade6-5488de51e4aa
The winner receives 2000 sats!

Improvement

Hasn't integrated with the actual Ark wallet so

  • No Bet Placement: Players aren't actually sending their 1000 sats to the lottery pot
  • No Payout: The winner isn't receiving the 2000 sats

TODO:

  • Bet Collection: When players commit, they should actually send their bet amount to a lottery pot address
  • Pot Management: The lottery should hold the combined bets in escrow
  • Winner Payout: When the game completes, transfer the full pot to the winner
  • Refund: If game aborts, refund bets to players

@pingu-73
Copy link
Owner Author

Gameflow Demonstration:

~/Desktop/proposal/testing/arkive-sdk zero-collateral
❯ coinflip create alice-wallet 500
2025-06-30T03:05:18.968802Z  INFO arkive_lottery::game: Player ec444c79-1e90-4198-8da0-876fd5e437fe joined game 657b5295-0172-498c-b0a3-176afffe2705
Created new game with real betting!
Game ID: 657b5295-0172-498c-b0a3-176afffe2705
Your Player ID: ec444c79-1e90-4198-8da0-876fd5e437fe
Bet Amount: 500 sats
Pot Wallet: pot_d6b8eae1-0516-44de-a802-664a25608031
Pot Address: tark1lfeudey8dlajmlykr4mrej56h3eafwywlju0telljtw9t6d2257crywaqmkzrkdhl4hnuly8hn5n9qlhu7lx7wu90sl6x4fg05cxqmqz4mrjf
Waiting for second player to join...

Share this command with another player:
coinflip join <their-wallet> 657b5295-0172-498c-b0a3-176afffe2705

~/Desktop/proposal/testing/arkive-sdk zero-collateral 11s
❯ coinflip join bob-wallet 657b5295-0172-498c-b0a3-176afffe2705
Joined game 657b5295-0172-498c-b0a3-176afffe2705!
Your Player ID: dc982c4d-b4c6-499e-a8c3-a388a97290e4
Game is now ready for betting!

Both players must now place their bets:
coinflip bet bob-wallet 657b5295-0172-498c-b0a3-176afffe2705

~/Desktop/proposal/testing/arkive-sdk zero-collateral 10s
❯ coinflip bet bob-wallet 657b5295-0172-498c-b0a3-176afffe2705
DEBUG: Pot address: 'tark1lfeudey8dlajmlykr4mrej56h3eafwywlju0telljtw9t6d2257crywaqmkzrkdhl4hnuly8hn5n9qlhu7lx7wu90sl6x4fg05cxqmqz4mrjf'
DEBUG: Player wallet: bob-wallet
DEBUG: Bet amount: 500 sats
DEBUG: Transaction successful: 4d52f862e28321ff5b6fdfe9d590413cd20d21c6be08308caa7509705159018f
Bet placed successfully!
Amount: 500 sats
Transaction ID: 4d52f862e28321ff5b6fdfe9d590413cd20d21c6be08308caa7509705159018f

Waiting for other player to place their bet...

~/Desktop/proposal/testing/arkive-sdk zero-collateral 9s
❯ coinflip bet alice-wallet 657b5295-0172-498c-b0a3-176afffe2705
DEBUG: Pot address: 'tark1lfeudey8dlajmlykr4mrej56h3eafwywlju0telljtw9t6d2257crywaqmkzrkdhl4hnuly8hn5n9qlhu7lx7wu90sl6x4fg05cxqmqz4mrjf'
DEBUG: Player wallet: alice-wallet
DEBUG: Bet amount: 500 sats
DEBUG: Transaction successful: 09cec6d3ccbe9f2dcf66ccf01d019f174e5f447695cbe162b4416e995f15760e
Bet placed successfully!
Amount: 500 sats
Transaction ID: 09cec6d3ccbe9f2dcf66ccf01d019f174e5f447695cbe162b4416e995f15760e

Both players have placed their bets!
The commitment phase can now begin:
coinflip commit alice-wallet 657b5295-0172-498c-b0a3-176afffe2705

~/Desktop/proposal/testing/arkive-sdk zero-collateral 10s
❯ arkive ark round pot_d6b8eae1-0516-44de-a802-664a25608031
2025-06-30T03:09:12.227457Z  INFO arkive_core::ark: Connected to Ark server
Participating in round for wallet 'pot_d6b8eae1-0516-44de-a802-664a25608031'...
2025-06-30T03:09:13.661954Z  INFO arkive_core::storage::boarding_store: Saved boarding output: 447923641aaa2c8ca1caee7f49494469c91c27178b0104c59c23880da88ba315:2 with 350 sats
2025-06-30T03:09:13.662019Z  INFO arkive_core::ark: Detected and stored boarding output: 447923641aaa2c8ca1caee7f49494469c91c27178b0104c59c23880da88ba315:2 with 350 sats
2025-06-30T03:09:13.662810Z  INFO arkive_core::ark: Participating in round with 0 VTXOs and 1 boarding outputs
2025-06-30T03:09:13.662838Z  INFO arkive_core::ark: Calling client.board()...
2025-06-30T03:09:27.177503Z  INFO arkive_core::ark: client.board() returned success
2025-06-30T03:09:27.994516Z  INFO arkive_core::ark: VTXOs after round: 1
2025-06-30T03:09:28.919693Z  INFO arkive_core::storage::boarding_store: Saved boarding output: 447923641aaa2c8ca1caee7f49494469c91c27178b0104c59c23880da88ba315:2 with 350 sats
2025-06-30T03:09:28.919743Z  INFO arkive_core::ark: Detected and stored boarding output: 447923641aaa2c8ca1caee7f49494469c91c27178b0104c59c23880da88ba315:2 with 350 sats
2025-06-30T03:09:31.109367Z  INFO arkive_core::ark: Recorded transaction: 4d52f862e28321ff5b6fdfe9d590413cd20d21c6be08308caa7509705159018f with amount: 500 sats
2025-06-30T03:09:31.110465Z  INFO arkive_core::ark: Recorded transaction: 09cec6d3ccbe9f2dcf66ccf01d019f174e5f447695cbe162b4416e995f15760e with amount: 500 sats
2025-06-30T03:09:31.111417Z  INFO arkive_core::ark: Recorded transaction: 447923641aaa2c8ca1caee7f49494469c91c27178b0104c59c23880da88ba315 with amount: 350 sats
2025-06-30T03:09:31.111431Z  INFO arkive_core::ark: Synced wallet 5f36e9b1-db6d-4d56-8042-0c06845ffbb6 with Ark server
2025-06-30T03:09:31.111441Z  INFO arkive_core::ark: Successfully participated in round: round_1751252971
Successfully participated in round!
Round transaction ID: round_1751252971

~/Desktop/proposal/testing/arkive-sdk zero-collateral 22s
❯ coinflip commit alice-wallet 657b5295-0172-498c-b0a3-176afffe2705
Commitment submitted for game 657b5295-0172-498c-b0a3-176afffe2705!
Your Player ID: ec444c79-1e90-4198-8da0-876fd5e437fe
Your secret (save this for reveal): bcade7153547ca92b1474f274bb141481ae570d80e4e5483a174f6e47a8bdf59

Waiting for other player to commit...

~/Desktop/proposal/testing/arkive-sdk zero-collateral
❯ coinflip commit bob-wallet 657b5295-0172-498c-b0a3-176afffe2705
Commitment submitted for game 657b5295-0172-498c-b0a3-176afffe2705!
Your Player ID: dc982c4d-b4c6-499e-a8c3-a388a97290e4
Your secret (save this for reveal): 60fa8ec56a13fec6d31577d2abedcc46a61fdf504d793d2ccacaa24f45754b36

Both players have committed! Now reveal your commitment:
coinflip reveal bob-wallet 657b5295-0172-498c-b0a3-176afffe2705 60fa8ec56a13fec6d31577d2abedcc46a61fdf504d793d2ccacaa24f45754b36

~/Desktop/proposal/testing/arkive-sdk zero-collateral
❯ coinflip reveal alice-wallet 657b5295-0172-498c-b0a3-176afffe2705 bcade7153547ca92b1474f274bb141481ae570d80e4e5483a174f6e47a8bdf59
Commitment revealed for game 657b5295-0172-498c-b0a3-176afffe2705!
Waiting for other player to reveal...

~/Desktop/proposal/testing/arkive-sdk zero-collateral
❯ coinflip reveal bob-wallet 657b5295-0172-498c-b0a3-176afffe2705 60fa8ec56a13fec6d31577d2abedcc46a61fdf504d793d2ccacaa24f45754b36
Commitment revealed for game 657b5295-0172-498c-b0a3-176afffe2705!

------ GAME COMPLETED! ------
═══════════════════════════════════
Winner: ec444c79-1e90-4198-8da0-876fd5e437fe
Prize: 1000 sats

Processing payout...
Payout successful!
1000 sats transferred to winner
Transaction ID: d8bc400c882b3eb2a56c469303b39497820c68e458d8e75499f8a7227e988434
Remaining pot balance: 0 sats

Comment on lines +29 to +31
pub fn from_hash(hash: Vec<u8>) -> Self {
Self { hash, secret: None }
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the impl From<Vec>``

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds a full zero-collateral lottery system with both a CLI client and a reusable Rust library.

  • Introduces a coinflip-cli binary that manages game lifecycle (create, join, bet, commit, reveal, status, list) and persists state locally.
  • Implements a new arkive-lottery crate with TwoPlayerGame, Player, and a hash‐based commit/reveal scheme.
  • Updates the workspace manifest to include the new crates and their dependencies.

Reviewed Changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
coinflip-cli/src/main.rs CLI entrypoint using clap and dispatching subcommands
coinflip-cli/src/commands/mod.rs Command handlers, JSON-based game storage, and user prompts
coinflip-cli/Cargo.toml Defines the coinflip-cli package and its dependencies
arkive-lottery/src/lib.rs Public re-exports and helper functions for the lottery crate
arkive-lottery/src/game.rs Core TwoPlayerGame logic for player management, betting, and payouts
arkive-lottery/src/player.rs Player struct with commitment and betting methods
arkive-lottery/src/commitment/scheme.rs Commitment trait implementation and struct
arkive-lottery/src/commitment/mod.rs HashCommitment implementation and helper functions
arkive-lottery/src/error.rs LotteryError definitions
arkive-lottery/Cargo.toml Defines the arkive-lottery package and its dependencies
Cargo.toml Adds coinflip-cli and arkive-lottery to the workspace
Comments suppressed due to low confidence (4)

coinflip-cli/src/commands/mod.rs:548

  • [nitpick] The ???? in the error message is unclear. Simplify to something like Payout failed: {} to make it more professional and user-friendly.
                println!("Payout failed ????: {}", e);

arkive-lottery/src/game.rs:29

  • [nitpick] There are no unit tests for TwoPlayerGame flows (bet placement, commitment, reveal, payout). Adding tests will help ensure protocol correctness and guard against regressions.
pub struct TwoPlayerGame {

coinflip-cli/src/commands/mod.rs:587

  • chrono::DateTime does not have a from_timestamp constructor. Use Utc.timestamp(deadline, 0) or NaiveDateTime::from_timestamp followed by DateTime::from_utc instead.
        let dt = chrono::DateTime::from_timestamp(deadline, 0).unwrap();

arkive-lottery/src/commitment/scheme.rs:27

  • Calling RngCore::fill_bytes on rand::thread_rng() won’t compile. Instead, do let mut rng = rand::thread_rng(); rng.fill_bytes(&mut nonce);
        rand::RngCore::fill_bytes(&mut rand::thread_rng(), &mut nonce);

@@ -0,0 +1,698 @@
#![allow(unused_variables)]
Copy link
Preview

Copilot AI Jun 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] This allow attribute silences all unused-variable warnings; consider removing it and addressing any unused bindings explicitly to keep the code clean.

Suggested change
#![allow(unused_variables)]

Copilot uses AI. Check for mistakes.

let game_data = GameData {
id: game_id.to_string(),
bet_amount: amount,
state: format!("{:?}", info.state),
Copy link
Preview

Copilot AI Jun 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storing the game state as a formatted string and later matching on that string is brittle. Consider serializing the GameState enum directly or storing it as an enum in the JSON for type safety.

Suggested change
state: format!("{:?}", info.state),
state: info.state,

Copilot uses AI. Check for mistakes.

}

let pot_address = pot_wallet.get_ark_address().await?;
println!("DEBUG: Pot address: '{}'", pot_address.address);
Copy link
Preview

Copilot AI Jun 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Raw debug prints can clutter user output; consider using a logging framework (e.g., log::debug!) or removing these debug statements in production.

Copilot uses AI. Check for mistakes.

Copy link
Collaborator

@vincenzopalazzo vincenzopalazzo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass, rust code looks really good!

I need to validate code logic but for now the structure is fine.

Are you planning to have integration testing that allow to test the code in the CI? probably if you have the core package you can do it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not create a new cli, use the arkive-cli

@pingu-73 pingu-73 marked this pull request as draft June 30, 2025 10:12
@pingu-73
Copy link
Owner Author

Are you planning to have integration testing that allow to test the code in the CI? probably if you have the core package you can do it

I'm thinking to add jonhoo's rust-ci-config and have opened an issue for it too (#5 ). But I was thinking to first fix ark round participation logic before doing that.

for other issues I've not done cargo clippy yet will do it and fix things

@pingu-73 pingu-73 changed the title Zero-Collateral Lotteries [Proof Of Concept] Zero-Collateral Lotteries Jul 28, 2025
@pingu-73
Copy link
Owner Author

This PR is not to be merged. It's a proof of work for #18

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants