Skip to content

Commit aea3916

Browse files
authored
Merge pull request #17 from AztecProtocol/feat/add-basic-prediction-market
feat: add basic prediction market
2 parents 3e5328c + b2ce6c2 commit aea3916

File tree

13 files changed

+7313
-1
lines changed

13 files changed

+7313
-1
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
name: Prediction Market Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
paths:
11+
- "prediction_market_contract/**"
12+
- ".github/workflows/prediction-market-tests.yml"
13+
workflow_dispatch:
14+
15+
jobs:
16+
prediction-market-tests:
17+
name: Prediction Market Tests
18+
runs-on: ubuntu-latest
19+
env:
20+
AZTEC_ENV: sandbox
21+
AZTEC_VERSION: 3.0.0-devnet.4
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v5
26+
27+
- name: Set up Node.js
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: "22"
31+
32+
- name: Setup Bun
33+
uses: oven-sh/setup-bun@v2
34+
with:
35+
bun-version: 1.1.36
36+
37+
- name: Set up Docker
38+
uses: docker/setup-buildx-action@v3
39+
40+
- name: Install Aztec CLI
41+
run: |
42+
curl -s https://install.aztec.network > tmp.sh
43+
NON_INTERACTIVE=1 bash tmp.sh
44+
rm tmp.sh
45+
46+
- name: Update path
47+
run: echo "$HOME/.aztec/bin" >> $GITHUB_PATH
48+
49+
- name: Set Aztec version and start sandbox
50+
run: |
51+
aztec-up ${{ env.AZTEC_VERSION }}
52+
docker tag aztecprotocol/aztec:${{ env.AZTEC_VERSION }} aztecprotocol/aztec:latest
53+
aztec start --sandbox &
54+
55+
- name: Wait for sandbox to be ready
56+
run: |
57+
echo "Waiting for sandbox to start..."
58+
MAX_RETRIES=60
59+
for i in $(seq 1 $MAX_RETRIES); do
60+
if curl -s http://localhost:8080/status >/dev/null 2>&1; then
61+
echo "Sandbox is ready!"
62+
break
63+
fi
64+
if [ $i -eq $MAX_RETRIES ]; then
65+
echo "Sandbox failed to start after $MAX_RETRIES attempts"
66+
exit 1
67+
fi
68+
echo "Waiting... ($i/$MAX_RETRIES)"
69+
sleep 2
70+
done
71+
72+
- name: Install project dependencies
73+
working-directory: prediction_market_contract
74+
run: bun install
75+
76+
- name: Run Noir unit tests
77+
working-directory: prediction_market_contract
78+
run: aztec test
79+
timeout-minutes: 10
80+
81+
- name: Compile contract and generate artifacts
82+
working-directory: prediction_market_contract
83+
run: |
84+
aztec-nargo compile
85+
aztec-postprocess-contract
86+
aztec codegen target -o artifacts
87+
88+
- name: Run end-to-end tests
89+
working-directory: prediction_market_contract
90+
run: bun test
91+
timeout-minutes: 15
92+
93+
- name: Upload test results if failed
94+
if: failure()
95+
uses: actions/upload-artifact@v4
96+
with:
97+
name: test-logs
98+
path: |
99+
prediction_market_contract/tests/**/*.log
100+
retention-days: 7
101+
102+
- name: Cleanup
103+
if: always()
104+
run: |
105+
echo "Stopping Aztec sandbox..."
106+
pkill -f "aztec" || true
107+
docker stop $(docker ps -q) || true
108+
docker rm $(docker ps -a -q) || true

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
target
22
.DS_Store
3-
ivc
3+
ivc
4+
node_modules

prediction-market/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
target/
2+
artifacts/
3+
node_modules/
4+
dist/
5+
*.log
6+
.DS_Store

prediction-market/Nargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "prediction_market_contract"
3+
authors = [""]
4+
compiler_version = ">=0.25.0"
5+
type = "contract"
6+
7+
[dependencies]
8+
aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.5", directory = "noir-projects/aztec-nr/aztec" }
9+
uint_note = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v3.0.0-devnet.5", directory = "noir-projects/aztec-nr/uint-note" }

prediction-market/README.md

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# Prediction Market Contract
2+
3+
A prediction market implementation on Aztec using a **Constant Sum Market Maker (CSMM)** for binary outcomes with **full identity privacy**.
4+
5+
## Overview
6+
7+
This contract allows users to:
8+
- **Bet on binary outcomes** (YES/NO) **anonymously** - no one knows WHO placed a bet
9+
- **Hold fully private balances** - collateral and share holdings are all hidden
10+
- **Experience dynamic pricing** that adjusts based on market sentiment
11+
- **Get slippage protection** to prevent adverse price movements
12+
- **Single-transaction betting** using partial notes pattern
13+
14+
## Privacy Model
15+
16+
### What's Private
17+
18+
| Data | Privacy | Notes |
19+
|------|---------|-------|
20+
| Bettor identity | **PRIVATE** | Public function doesn't receive sender address |
21+
| Collateral balances | **PRIVATE** | Stored as private notes (UintNote) |
22+
| Share balances | **PRIVATE** | Stored as private notes (UintNote) |
23+
| Your bet (YES/NO) | **PRIVATE** | Hidden via partial notes |
24+
25+
### What's Public
26+
27+
| Data | Visibility | Why |
28+
|------|------------|-----|
29+
| Price changes | PUBLIC | Necessary for AMM pricing |
30+
| Trade amounts | PUBLIC | Affects price movement |
31+
| That someone bought YES/NO | PUBLIC | Observable from price changes |
32+
33+
### Privacy Architecture
34+
35+
The contract uses **partial notes** for private betting (like the [AMM contract](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/noir-contracts/contracts/amm_contract)):
36+
37+
```
38+
1. buy_outcome() [PRIVATE]
39+
|
40+
+-- Consumes private collateral notes
41+
+-- Creates change note if needed
42+
+-- Creates partial note commitment (hides owner)
43+
+-- Enqueues public call WITHOUT sender address
44+
v
45+
2. _process_buy() [PUBLIC]
46+
|
47+
+-- Calculates shares based on CSMM pricing
48+
+-- Updates YES/NO supplies (price changes)
49+
+-- Completes partial note with share amount
50+
v
51+
Shares appear in user's private balance (single tx!)
52+
```
53+
54+
Key privacy feature: The public `_process_buy()` function **does not receive the sender address**. It only knows WHAT was traded, not WHO traded.
55+
56+
## Usage
57+
58+
### Betting Flow (Single Transaction)
59+
60+
```typescript
61+
// Deposit collateral privately
62+
await market.methods.deposit(1000n).send({ from: myAddress }).wait()
63+
64+
// Buy outcome privately - single transaction!
65+
await market.methods.buy_outcome(
66+
true, // is_yes
67+
500n, // collateral_amount
68+
900n, // min_shares_out (slippage protection)
69+
).send({ from: myAddress }).wait()
70+
71+
// Your shares are immediately in your private balance!
72+
const myBalance = await market.methods.get_yes_balance(myAddress).simulate({ from: myAddress })
73+
```
74+
75+
### Collateral Management (All Private)
76+
77+
```typescript
78+
// Deposit collateral (private)
79+
await market.methods.deposit(1000n).send({ from: myAddress }).wait()
80+
81+
// Withdraw collateral (private)
82+
await market.methods.withdraw(500n).send({ from: myAddress }).wait()
83+
84+
// Check balance (view private notes)
85+
const balance = await market.methods.get_collateral_balance(myAddress).simulate({ from: myAddress })
86+
```
87+
88+
## Development
89+
90+
### Prerequisites
91+
92+
```bash
93+
# Install Aztec tools
94+
bash -i <(curl -s https://install.aztec.network)
95+
aztec-up 3.0.0-devnet.5
96+
97+
# Install dependencies
98+
yarn install
99+
```
100+
101+
### Building
102+
103+
```bash
104+
# Compile the contract
105+
aztec-nargo compile
106+
107+
# Post-process and generate TypeScript bindings
108+
aztec-postprocess-contract
109+
aztec codegen target -o artifacts
110+
```
111+
112+
### Testing
113+
114+
#### Noir Unit Tests
115+
116+
```bash
117+
aztec test
118+
```
119+
120+
Tests the CSMM pricing functions:
121+
- Share calculations at various price points
122+
- Price calculations and invariants
123+
- Edge cases
124+
125+
#### End-to-End Tests
126+
127+
```bash
128+
# Start Aztec sandbox (in separate terminal)
129+
aztec start --sandbox
130+
131+
# Run tests
132+
yarn test
133+
```
134+
135+
Tests the full private betting flow:
136+
- Contract deployment
137+
- Private deposit/withdraw
138+
- Private buy_outcome (single tx with partial notes)
139+
- Price movements
140+
- Balance privacy
141+
142+
## Constant Sum Market Maker (CSMM)
143+
144+
### Core Invariant
145+
```
146+
price_YES + price_NO = 1
147+
```
148+
149+
### Pricing Formula
150+
```
151+
price_YES = yes_supply / (yes_supply + no_supply)
152+
shares_out = collateral_in / current_price
153+
```
154+
155+
### Example
156+
157+
```
158+
Initial: YES=5000, NO=5000, price_YES=50%
159+
160+
Alice buys 1000 collateral of YES:
161+
- Shares received: 1000 / 0.50 = 2000 YES
162+
- New YES supply: 7000
163+
- New price_YES: 7000 / 12000 = 58.3%
164+
```

prediction-market/jest.config.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export default {
2+
testEnvironment: 'node',
3+
transform: {
4+
'^.+\\.(t|j)sx?$': ['@swc/jest'],
5+
'^.+\\.mjs$': ['@swc/jest'],
6+
},
7+
extensionsToTreatAsEsm: ['.ts'],
8+
moduleNameMapper: {
9+
'^(\\.{1,2}/.*)\\.js$': '$1',
10+
},
11+
transformIgnorePatterns: [
12+
'node_modules/(?!(@aztec|ohash|fake-indexeddb)/)',
13+
],
14+
testMatch: ['**/tests/**/*.test.ts'],
15+
testTimeout: 120000,
16+
verbose: true,
17+
};

prediction-market/package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "prediction_market_contract",
3+
"type": "module",
4+
"scripts": {
5+
"clean": "rm -rf target artifacts",
6+
"ccc": "aztec-nargo compile && aztec-postprocess-contract && aztec codegen target -o artifacts",
7+
"test": "jest",
8+
"test:watch": "jest --watch",
9+
"test:noir": "aztec test"
10+
},
11+
"devDependencies": {
12+
"@jest/globals": "^29.0.0",
13+
"@swc/core": "^1.3.0",
14+
"@swc/jest": "^0.2.0",
15+
"@types/jest": "^29.0.0",
16+
"@types/node": "^20.0.0",
17+
"fake-indexeddb": "^6.2.5",
18+
"jest": "^29.0.0",
19+
"tsx": "^4.21.0",
20+
"typescript": "^5.0.0"
21+
},
22+
"peerDependencies": {
23+
"typescript": "^5.0.0"
24+
},
25+
"dependencies": {
26+
"@aztec/accounts": "3.0.0-devnet.5",
27+
"@aztec/aztec.js": "3.0.0-devnet.5",
28+
"@aztec/pxe": "3.0.0-devnet.5",
29+
"@aztec/test-wallet": "3.0.0-devnet.5"
30+
}
31+
}

prediction-market/run-tests.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/bin/bash
2+
set -e
3+
4+
echo "=== Prediction Market Contract Tests ==="
5+
echo ""
6+
7+
# Check if sandbox is running
8+
if ! curl -s http://localhost:8080/status >/dev/null 2>&1; then
9+
echo "Error: Aztec sandbox is not running!"
10+
echo "Please start it with: aztec start --sandbox"
11+
exit 1
12+
fi
13+
14+
echo "1. Cleaning previous builds..."
15+
rm -rf target artifacts
16+
17+
echo ""
18+
echo "2. Running Noir unit tests..."
19+
aztec test
20+
21+
echo ""
22+
echo "3. Compiling contract..."
23+
aztec-nargo compile
24+
25+
echo ""
26+
echo "4. Post-processing contract..."
27+
aztec-postprocess-contract
28+
29+
echo ""
30+
echo "5. Generating TypeScript bindings..."
31+
aztec codegen target -o artifacts
32+
33+
echo ""
34+
echo "6. Installing dependencies..."
35+
bun install
36+
37+
echo ""
38+
echo "7. Running end-to-end tests..."
39+
bun test
40+
41+
echo ""
42+
echo "=== All tests passed! ==="

0 commit comments

Comments
 (0)