Skip to content

imiskii/TaskBoard

Repository files navigation

TaskBoard (A decentralized platform for CTF-style challenges using Ethereum, IPFS, and zkSNARKs.)

See a small blog about this dApp.

TaskBoard is a dApp for creating and solving CTF-like tasks using smart contracts, IPFS, and zero-knowledge proofs (ZKP). Users solve challenges by proving knowledge of a hidden secret without revealing it. Successful solvers are rewarded with task-specific tokens.

To ensure trustless and scalable operation:

  • Solutions are verified automatically (no manual approval).
  • Tasks and descriptions are stored off-chain via IPFS.
  • Proof validation is handled using ZK circuits.
  • Submissions remain private to avoid copying.
  • Rewards issued as non-transferable ERC-1155 tokens.

Tech stack

  • Frontend – React
  • Backend – Node.js (Fastify) + Postgres
  • Smart contracts – Solidity (ERC-1155, AccessControl)
  • Storage – IPFS (local - Kubo IPFS / Pinata)
  • Proof system – snarkjs + Groth16

How it works

  1. Task creation – Creator commits a secret (Poseidon hash + salt) stored on IPFS.
  2. Solving – Solver submits a ZKP proving they know the secret.
  3. Verification – Smart contract checks the proof and mints a reward token.

Set up

  1. Compile the circuit and generate a trusted setup with make circuit (testing only).
  2. Export smart contract ABI with make export-task-manager-abi.
  3. Start the Postgres DB and use make delete-db and make init-db.
  • Postgres has to have user app and created database called task_board_db.
  1. Start Anvil and deploy smart contracts with make deploy-local and add creator add-creator-local.
  • The creator is Anvil's account (1) with address 0x70997970C51812dc3A010C7d01b50e0d17dc79C8, add it to your wallet (e.g., MetaMask).
  1. Start Kubo IPFS ipfs daemon.
  2. Start the backend from /backend directory with npm run dev.
  3. Start the frontend from /frontend directory with npm run dev.

Environment files

Root .env (for smart contracts)

### ENV for local Anvil node
PRIVATE_KEY_LOCAL=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
PRIVATE_KEY_CREATOR=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
PRIVATE_KEY_SOLVER=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a

CREATOR_ADDR=0x70997970C51812dc3A010C7d01b50e0d17dc79C8

TASK_MANAGER_ADDR=0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9
TASK_ACCESS_ADDR=0x5FbDB2315678afecb367f032d93F642f64180aa3

TASK_ID_TO_DEACTIVATE=1

### ENV for Sepolia deployment

PRIVATE_KEY=0xYOUR_PRIVATE_KEY # Wallet private key
ETHERSCAN_API_KEY=YOUR_ETHERSCAN_KEY # Etherscan API key (for verification)
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/<YOUR_ALCHEMY_KEY> # RPC provider (Alchemy)

Backend .env

SERVER_PORT=3000
IPFS_STORAGE_MODE='local' # 'dev', 'local', or 'prod'
IPFS_LOCAL_API_URL='http://127.0.0.1:5001' # if IPFS_STORAGE_MODE='local', then this is the API URL of the local IPFS node
IPFS_LOCAL_GATEWAY_URL='http://127.0.0.1:8080' # if IPFS_STORAGE_MODE='local', then this is the gateway URL of the local IPFS node
PINATA_API_KEY='<Pinata API key>' # if IPFS_STORAGE_MODE='prod', then this is the Pinata API key
PINATA_JWT_TOKEN='<Pinata JWT token>' # if IPFS_STORAGE_MODE='prod', then this is the Pinata JWT token
PINATA_GATEWAY_URL='blush-peculiar-quail-924.mypinata.cloud' # if IPFS_STORAGE_MODE='prod', then this is the Pinata gateway URL
PINATA_TASKS_GROUP_ID='<Pinata tasks group ID>' # if IPFS_STORAGE_MODE='prod', then this is the Pinata tasks group ID
PINATA_IMAGES_GROUP_ID='<Pinata images group ID>' # if IPFS_STORAGE_MODE='prod', then this is the Pinata images group ID

LISTENER_MODE= 'local' # 'local' or 'prod'
INFURA_API_KEY='<Infura API Key>' # if LISTENER_MODE='prod', then this is the Infura API Key
CONTRACT_ADDRESS=0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 # TaskManager contract deployed address
START_BLOCK=0 # Needed for fetching history of events. This has to be number of block inside which the TaskManager contract was deployed
FINALITY_BLOCKS=5 # Number of blocks until events will be recorded into the database

DATABASE_USER='app'
DATABASE_PWD='app'
DATABASE_HOST='localhost'
DATABASE_NAME='task_board_db'
DATABASE_PORT=5432

Token metadata and Task Data

{
  "name": "Stego Sleuth",
  "description": "Proof of your ability to uncover secrets hidden in plain sight.",
  "image": "ipfs://<cid>",
  "task": {
    "title": "Steganography in the Image",
    "description": "A PNG file hides a message in its least significant bits. Extract it to find the secret number.",
    "difficulty": "Easy",
    "tags": ["stego", "forensics", "binary"],
    "createdBy": "0x1234abcd...",
    "createdAt": 1729849200,
    "requirements": ["steganography tools", "hex editor"],
    "resources": ["ipfs://<cid>"]
  }
}

About

Decentralized platform for posting, claiming, and resolving tasks.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors