Skip to content

P1750A/gitcoin

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitCoin ⛓

A fully decentralized token ecosystem that runs entirely on GitHub. No servers, no wallets, no gas fees — just forks, pull requests, and consensus.

Live Balance Explorer: https://volta2030.github.io/gitcoin/ — Balances, Transactions, Validators tabs


How It Works

Blockchain concept GitCoin equivalent
Full node Fork of this repository
Transaction Pull Request with UTXO file changes
Block Merge commit on main
Hash chain Git commit history
Validator / miner Any GitHub account with a registered public key in validators/pubkeys.json
Consensus ⌈2/3⌉ selected validators comment /approve
Double-spend guard Git merge conflict (two PRs can't delete the same file)
Total supply 4,294,967,295 GTC (fixed, no inflation)
Minimum unit 1 GTC (integer amounts only)

Transaction lifecycle

1. Pull the latest main branch
2. Run create_transaction.py — builds, signs, writes UTXO files, and git rm's inputs automatically
3. git add utxo/ && git commit && git push to a new branch, open a PR
4. validate-tx.yml verifies signature and UTXO ownership
5. On success: tx-valid label + Validator Vote Requested comment posted (same workflow, no separate trigger)
6. Selected validators comment /approve on the PR
7. When ⌈2/3⌉ approvals are reached, PR can be merged
8. update-pages.yml rebuilds the explorer (Balances / Transactions / Validators)

Non-TX PRs (key registration, code changes) skip validation entirely and get immediate success status on both required checks, so they are never blocked.


Requirements

pip install cryptography

You also need:


Quick Start

Step 1 — Fork this repository

Click Fork at the top of this page. Your fork is your full node — it contains the entire ledger history.

Step 2 — Generate your Ed25519 identity

git clone https://github.com/YOUR_USERNAME/gitcoin
cd gitcoin
python3 .github/scripts/generate_keypair.py

Output:

⚠️  PRIVATE KEY — Keep this secret, never commit it:
  <your-private-key-base64url>

✅  PUBLIC KEY — Share this in your REGISTER_KEY PR:
  <your-public-key-base64url>

Store your private key in a password manager. If you lose it, you lose access to your coins. Never commit it to any repository.

Step 3 — Register your public key

Before you can send GTC, your public key must be in validators/pubkeys.json.

Create a PR to this repo's main branch with:

Changed file — add your entry to validators/pubkeys.json:

{
  "existing_user": "their_key",
  "YOUR_GITHUB_USERNAME": "YOUR_PUBLIC_KEY_BASE64URL"
}

PR title: register: YOUR_GITHUB_USERNAME

PR body: anything (no TX_VERSION needed — the workflow detects this is not a TX and auto-approves both required status checks immediately).

Once a maintainer merges the PR, you can start transacting — and you are automatically added to the validator pool.


Checking Your Balance

Visit the live balance explorer:

https://<owner>.github.io/gitcoin/

Or inspect the ledger directly:

git pull origin main
cat docs/ledger.json

Or scan your UTXOs manually:

grep -rl '"owner": "YOUR_USERNAME"' utxo/

Sending GTC

Step 1 — Pull the latest state

git pull origin main

Step 2 — Find your UTXOs

grep -rl '"owner": "YOUR_USERNAME"' utxo/

Note the txid values (the filenames without .json).

Step 3 — Run the transaction builder

python3 .github/scripts/create_transaction.py

You will be prompted for:

  • Your GitHub username
  • Your private key
  • Recipient username
  • Amount to send (GTC)
  • UTXO txids to spend (comma-separated)
  • Optional memo

The script outputs the exact PR body to copy and the file changes to make. It can also write the output UTXO files automatically.

Step 4 — Commit and push the changes

The script does git rm on input UTXOs and writes output files automatically. Just run:

git add utxo/
git commit -m "tx: YOUR_USERNAME → RECIPIENT 50 GTC"
git push origin <new-branch-name>

Step 5 — Open a PR

Open a Pull Request to this repository's main branch.

  • PR title: tx: YOUR_USERNAME → RECIPIENT 50 GTC
  • PR body: paste the TX_VERSION: 1 ... block from the script output

Step 6 — Wait for consensus

validate-tx.yml runs automatically. If valid:

  • tx-valid label is attached
  • A Validator Vote Requested comment is posted listing selected validators and deadline
  • Selected validators comment /approve — anyone in validators/pubkeys.json is eligible
  • When ⌈2/3⌉ approvals are reached, merge the PR

Becoming a Validator

Anyone with a registered public key in validators/pubkeys.json is a validator.

How to join

  1. Generate your keypair: python3 .github/scripts/generate_keypair.py
  2. Open a PR adding "YOUR_USERNAME": "YOUR_PUBLIC_KEY" to validators/pubkeys.json
  3. Once merged, you are immediately in the validator pool

Scoring (optional metadata)

Scores in validators/registry.json influence selection probability. Anyone not listed defaults to 100 points.

Action Points
Comment /approve on a valid TX +20
Submitting a valid TX that gets merged +5

Inactivity penalty: −10 points per week with no /approve activity.

How to vote

When a transaction PR is validated:

  1. You receive a GitHub @mention in the Validator Vote Requested comment.
  2. Visit the PR, review the utxo/ file changes.
  3. Comment exactly /approve to cast your vote.

You have 48 hours. If the threshold is not reached, the PR is automatically expired.


Transaction Reference

Transfer (TX_VERSION: 1)

TX_VERSION: 1
FROM: alice
TO: bob
AMOUNT: 50
INPUT_TXIDS: a1b2c3d4e5f6...,d4e5f6a1b2c3...
OUTPUT_TO_TXID: f7a8b9c0d1e2...
OUTPUT_CHANGE_TXID: e3d4c5b6a7f8...
MEMO: payment for work
SIGNATURE: <base64url Ed25519 signature>
Field Required Description
TX_VERSION Must be 1
FROM Must match PR author's GitHub login
TO Recipient GitHub username
AMOUNT Integer GTC to send (minimum: 1 GTC)
INPUT_TXIDS Comma-separated txids of UTXOs you are spending
OUTPUT_TO_TXID txid of new UTXO file added for the recipient
OUTPUT_CHANGE_TXID if change txid of change UTXO returned to you
MEMO optional Free-text note
SIGNATURE Ed25519 signature over the canonical message

Conservation rule: sum(inputs) == AMOUNT + change. No GTC can be created or destroyed.

Note: All amounts are integers. The minimum transactable unit is 1 GTC. Decimal amounts are not supported.

Key Registration (TX_VERSION: REGISTER_KEY)

TX_VERSION: REGISTER_KEY
USERNAME: alice
PUBLIC_KEY: <base64url Ed25519 public key>

PR must only modify validators/pubkeys.json by adding one new entry.


UTXO File Format

Each file in utxo/ represents one unspent coin:

{
  "txid": "a1b2c3d4...",
  "owner": "alice",
  "amount": 100,
  "unit": "GTC",
  "created_at_block": "<merge commit SHA>",
  "created_at_height": 42
}

The filename must match the txid field: utxo/<txid>.json.

Computing a txid:

import hashlib
txid = hashlib.sha256(f"{owner}{amount}{created_at_block}".encode()).hexdigest()

Founder / Repository Setup Guide

Follow these steps once when deploying a new GitCoin instance.

1. Create the repository

Create a new public GitHub repository. Do not enable Branch Protection yet.

2. Generate your keypair

python3 .github/scripts/generate_keypair.py

3. Compute your genesis txid

import hashlib
owner = "YOUR_GITHUB_USERNAME"
amount = 4294967295
block_hash = "0" * 64
txid = hashlib.sha256(f"{owner}{amount}{block_hash}".encode()).hexdigest()
print(txid)

4. Edit the genesis files

genesis/genesis.json — replace REPLACE_WITH_FOUNDER_USERNAME and REPLACE_WITH_GENESIS_TXID.

validators/pubkeys.json — replace placeholders with your username and public key.

validators/registry.json — replace REPLACE_WITH_FOUNDER_USERNAME with your username.

Create utxo/<genesis_txid>.json:

{
  "txid": "<your computed genesis txid>",
  "owner": "YOUR_GITHUB_USERNAME",
  "amount": 4294967295,
  "unit": "GTC",
  "created_at_block": "0000000000000000000000000000000000000000000000000000000000000000",
  "created_at_height": 0
}

5. Commit everything to main

git add .
git commit -m "genesis: initialize GitCoin ledger"
git push origin main

6. Enable GitHub Pages

In your repository Settings → Pages:

  • Set Source to GitHub Actions

7. Configure Branch Protection (do this last)

In Settings → Branches → Add rule for main:

  • Require status checks to pass before merging
    • Add required check: validate-tx / validate
    • Add required check: consensus-check / passed
  • Require branches to be up to date before merging
  • Include administrators ← CRITICAL: do not skip this
  • Allow auto-merge
  • Allow force pushes — leave unchecked
  • Allow deletions — leave unchecked

After enabling "Include administrators", even you cannot merge without going through consensus. This is intentional — it is the foundation of the system's trustlessness.

8. Create required labels

In your repository Issues → Labels, create:

  • tx-valid (color: #2ea043)
  • tx-invalid (color: #f85149)
  • tx-expired (color: #8b949e)

Security Notes

Property How it is enforced
No stored bot keys All workflows use only ephemeral GITHUB_TOKEN (auto-issued per run, expires on completion)
No admin bypass Branch Protection includes administrators
No double-spend Git merge conflict blocks the second PR deleting the same UTXO file
No code injection from PR pull_request_target runs main branch code; the PR head branch is never checked out or executed
No shell injection from PR body PR body is parsed as plain text by Python, never interpolated into shell commands
Signature forgery Ed25519 signatures are verified against the registered public key for each sender
Sybil validators Public key registration required; key must be merged into main via consensus

Architecture Overview

.github/
├── workflows/
│   ├── validate-tx.yml        pull_request_target → verify TX sig; on success posts validator
│   │                          vote comment inline (no separate assign-validators trigger needed)
│   │                          non-TX PRs get immediate success on both required checks
│   ├── consensus-check.yml    issue_comment → count /approve from pubkeys.json validators
│   ├── expire-tx.yml          schedule (6h) → close PRs past 48h deadline
│   └── update-pages.yml       push to main (utxo/** or validators/**) → rebuild + deploy Pages
└── scripts/
    ├── validate_tx.py          Core validation logic (TRANSFER + REGISTER_KEY)
    ├── update_ledger.py        UTXO scanner → ledger.json with balances, TX history, validators
    ├── generate_keypair.py     User tool: generate Ed25519 keypair
    └── create_transaction.py   User tool: build, sign, write files, git rm inputs automatically

utxo/                          One JSON file per unspent coin
validators/
    pubkeys.json               Ed25519 public keys per GitHub username (validator pool)
    registry.json              Optional scoring metadata (score, last_active)
genesis/
    genesis.json               Genesis block metadata
docs/
    index.html                 Explorer UI: Balances / Transactions / Validators tabs
    ledger.json                Snapshot rebuilt after every merge to main

Portability

If GitHub ever becomes unavailable, the entire ledger history is preserved in every fork's git log. The same workflow logic can be migrated to:

  • GitLab (GitLab CI/CD)
  • Gitea / Forgejo (Gitea Actions)
  • Radicle (decentralized git hosting)

The UTXO files and commit history are the canonical truth. No data lives outside the repository.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors