Skavenge is an NFT-based scavenger hunt game implemented on Ethereum. Players can mint, solve, and trade clues as NFTs using ElGamal encryption and cryptographic proofs for secure transfers.
Skavenge combines blockchain technology, cryptography, and gamification to create a decentralized scavenger hunt where:
- Clues are ERC721 NFTs with encrypted content
- Solutions are verified on-chain through hash matching
- Clues can be traded securely between players using cryptographic proofs
- Solved clues earn point values that determine chances of winning prizes
- Optional solve rewards provide immediate ETH incentives
/skavenge
├── cmd/
│ ├── generate-query-cli/ # CLI generator for contract queries
│ ├── skavenge-query/ # Generated CLI tool (auto-generated)
│ └── setup/ # Contract deployment tool
├── eth/
│ ├── bindings/ # Go bindings for Ethereum contracts
│ ├── build/ # Compiled contract artifacts
│ └── skavenge.sol # Solidity smart contract
├── linked-accounts-gateway/ # Gateway for account linking and transfer data
├── skavenger-extension/ # Browser extension for key management
├── tests/
│ ├── util/ # Test utilities
│ ├── mint_test.go # Tests for minting clues
│ ├── solve_test.go # Tests for solving clues
│ └── transfer_test.go # Tests for transferring clues
├── webapp/ # React web application
├── zkproof/ # Cryptographic proof utilities
└── Makefile # Build and test automation
- Minting Clues: Create new clues with ElGamal-encrypted content, solution hashes, point values, and optional solve rewards
- Solving Clues: Attempt to solve clues by submitting solutions that are verified against on-chain hashes
- Trading Clues: Securely transfer unsolved clues to other players using cryptographic proof verification
- Point System: Solved clues award point values (1-5) that determine a player's chances of winning the grand prize
- Solve Rewards: Optional ETH rewards automatically distributed when a clue is solved
- Transfer Protection: Prevents transfer of solved clues to maintain game integrity
- Account Linking: Links Ethereum addresses to Skavenge public keys for secure operations
- CLI Query Tool: Auto-generated command-line interface for contract queries
- Smart Contracts: Solidity ^0.8.20 with OpenZeppelin ERC721Enumerable
- Cryptography: ElGamal encryption on secp256k1 curve, ECDSA signatures
- Blockchain: Ethereum (compatible with any EVM chain)
- Frontend: React 18 with Web3.js
- Backend: Go with ethereum/go-ethereum client
- Gateway: Go HTTP server for account linking and transfer coordination
- Browser Extension: Chrome extension for secure key management
- Testing: Go test suite with Hardhat local blockchain
- Container Orchestration: Docker Compose
The easiest way to run Skavenge locally is using Docker Compose, which sets up all required services.
- Docker and Docker Compose
- Git
- Chrome browser
- MetaMask browser extension
-
Clone the repository:
git clone https://github.com/deelawn/skavenge.git cd skavenge -
Install and configure MetaMask:
- Install the MetaMask browser extension
- Create a new Ethereum account specifically for Skavenge (recommended for security)
- Export the private key from MetaMask:
- Click the account menu (three dots)
- Select "Account details"
- Click "Show private key"
- Enter your MetaMask password
- Copy the private key
-
Install and configure the Skavenger extension:
- Open Chrome and navigate to
chrome://extensions/ - Enable "Developer mode" (toggle in top right)
- Click "Load unpacked"
- Select the
skavenger-extensiondirectory from this repository - Note the extension ID (should be
hnbligdjmpihmhhgajlfjmckcnmnofbn) - Click on the Skavenger extension icon in your browser
- Generate a new key pair by clicking "Generate New Keys"
- Set a password to encrypt your keys
- Export the private key:
- Click "Export Keys"
- Enter your password
- Copy the private key (the hex string without "0x" prefix)
- Open Chrome and navigate to
-
Create and configure test-config.json:
cp test-config.json.example test-config.json
Edit
test-config.jsonand add your private keys:{ "privateKey": "YOUR_METAMASK_PRIVATE_KEY_HERE", "skavengePrivateKey": "YOUR_SKAVENGER_PRIVATE_KEY_HERE", "hardhatUrl": "http://hardhat:8545" }Important: Both private keys should be hex strings without the "0x" prefix.
-
Start all services:
make start-with-setup
This command will:
- Start a local Hardhat Ethereum node
- Deploy the Skavenge smart contract
- Start the linked accounts gateway
- Start the React web application
Services will be available at:
- Hardhat Node: http://localhost:8545
- Web Application: http://localhost:8080
- Gateway API: http://localhost:4591
-
Access the web app:
- Open http://localhost:8080 in your browser
- Connect your Skavenger extension
- Connect MetaMask
- Start playing!
make stopIf you make changes to the code:
# Rebuild all images
make docker-build
# Restart with new images
make start-with-setupThe project includes comprehensive tests for all smart contract functionality.
# Build and run tests in containers
make docker-test# Start Hardhat node
make docker-up
# Run tests
go test ./tests/...
# Clean up
make docker-down# Test minting
go test ./tests -run TestMint
# Test solving
go test ./tests -run TestSolve
# Test transfers
go test ./tests -run TestTransferThe Skavenge.sol contract is an ERC721Enumerable token with custom functionality:
- Each token represents an encrypted clue
- Clues store ElGamal-encrypted content, solution hashes, and metadata
- Players can list clues for sale and initiate secure transfers
- Transfer requires cryptographic proof verification to prevent cheating
- Solved clues cannot be transferred
A Go HTTP server that provides:
- Account Linking: Maps Ethereum addresses to Skavenge public keys via signature verification
- Transfer Coordination: Stores encrypted transfer data for secure clue transfers
- Signature Verification: Validates Ethereum and Skavenge ECDSA signatures
A Chrome extension that:
- Generates and stores secp256k1 key pairs
- Signs messages for authentication
- Performs ElGamal decryption
- Generates cryptographic proofs for transfers
- Keeps private keys secure (never exposed to web apps)
A React SPA that:
- Connects to MetaMask for blockchain transactions
- Connects to Skavenger extension for cryptographic operations
- Provides UI for minting, solving, and trading clues
- Manages the complete user experience
- Clue creator generates encrypted content using ElGamal encryption
- Creator submits transaction with encrypted content, solution hash, point value, and optional reward
- Contract mints a new NFT and stores the clue data
- Creator can list the clue for sale or attempt to solve it themselves
- Player who owns a clue can attempt to solve it
- Player submits their solution to
attemptSolution() - Contract hashes the solution and compares it to the stored hash
- If correct:
- Clue is marked as solved
- Point value is awarded to the player
- Solve reward (if any) is transferred to the player
- If incorrect, the transaction reverts
- Seller lists clue for sale using
setSalePrice() - Buyer initiates purchase, locking the price in the contract
- Seller generates re-encrypted content for buyer and provides proof
- Buyer verifies the proof
- Contract validates proof and completes transfer
- If any step times out, either party can cancel and reclaim funds
Used by the setup tool to deploy contracts and initialize the system. You must create this file with your private keys before running make start:
{
"privateKey": "YOUR_METAMASK_PRIVATE_KEY_HERE",
"skavengePrivateKey": "YOUR_SKAVENGER_PRIVATE_KEY_HERE",
"hardhatUrl": "http://hardhat:8545"
}Fields:
privateKey: Private key from your MetaMask account (without "0x" prefix)skavengePrivateKey: Private key from your Skavenger extension (without "0x" prefix)hardhatUrl: URL of the Hardhat node (usehttp://hardhat:8545for Docker,http://localhost:8545for local)
Auto-generated by the setup tool. Contains:
{
"contractAddress": "0x...",
"networkRpcUrl": "http://localhost:8545",
"chainId": 1337,
"gatewayUrl": "http://localhost:4591"
}This file is automatically created when you run make start.
make start- Start all services with Docker Composemake stop- Stop all servicesmake docker-build- Build all Docker imagesmake docker-test- Run tests in containersmake compile- Compile Solidity to Go bindingsmake compile-js- Compile Solidity to JavaScript ABImake generate-cli- Generate CLI query toolmake setup- Deploy contract (Docker)make setup-local- Deploy contract (local)
- Web Application README - Detailed webapp documentation
- Gateway README - Gateway API documentation
- Extension README - Browser extension guide
TBD