| File | Purpose |
|---|---|
src/contracts/MilestoneLock.cash |
CashScript smart contract source |
src/services/milestoneContract.js |
All Week 3 logic: mint, vote, release |
src/components/GovernancePanel.jsx |
New governance UI panel |
src/components/Dashboard.jsx |
Updated to include GovernancePanel |
src/components/WalletPanel.jsx |
Updated to expose wallet to parent |
1. Connect BCH Wallet (Week 2 panel)
↓
2. Lock BCH in Governance Panel (simulates contract funding)
↓ mints CashTokens (GOV tokens)
3. Use GOV tokens to vote YES/NO on milestones
↓ each token = 1 vote
4. If >50% YES → milestone approved → Release button appears
↓ calls wallet.send() on Chipnet
5. BCH sent from your wallet to the project team address ✅
npm install @cashscript/utils cashscriptnpm run devOpen: http://localhost:5173
File: src/contracts/MilestoneLock.cash
contract MilestoneLock(pubkey ownerPk, pubkey funderPk) {
function release(sig ownerSig) {
require(checkSig(ownerSig, ownerPk));
}
function refund(sig funderSig) {
require(checkSig(funderSig, funderPk));
}
}
What it means:
constructor params= baked into the contract at deploy timerelease()= only the project OWNER (who hasownerPk) can sign and unlockrefund()= the original FUNDER can always get their money back- The BCH sitting in this contract UTXO can only be spent via one of these two functions
- The 50% governance threshold is enforced in
milestoneContract.js— only callsrelease()after approval
CashTokens are native tokens on BCH — baked into the protocol (since CHIP-2022-02).
Types:
- Fungible tokens (FT) — like our GOV tokens — you can split and merge them
- Non-fungible tokens (NFT) — unique (not used here)
How we mint:
await wallet.send([
new TokenSendRequest({
cashaddr: wallet.cashaddr,
amount: 100, // mint 100 tokens
})
])The first time you send with TokenSendRequest without a category, it creates a genesis output — a brand new token type. The Transaction ID becomes the Token Category ID (like a contract address in Ethereum).
For a real deployment (beyond the hackathon MVP):
npm install -g cashccashc src/contracts/MilestoneLock.cash --output src/contracts/MilestoneLock.jsonThis creates a JSON artifact with the bytecode.
import { Contract, ElectrumNetworkProvider } from 'cashscript'
import artifact from './src/contracts/MilestoneLock.json' assert { type: 'json' }
const provider = new ElectrumNetworkProvider('chipnet')
const contract = new Contract(artifact, [ownerPubKey, funderPubKey], { provider })
console.log('Contract address:', contract.address)
// Fund this address with testnet BCH from the faucetconst contractInstance = new Contract(artifact, [ownerPk, funderPk], { provider })
const tx = await contractInstance.functions
.release(new SignatureTemplate(ownerKeypair))
.to(ownerAddress, contractBalance - 1000n) // keep 1000 sat for fee
.send()- Open http://localhost:5173
- Create a project with 2–3 milestones
- Click Connect Wallet (auto-generates a Chipnet wallet)
- Go to tbch.googol.cash, paste your wallet address, get free tBCH
- Wait 1–2 min, click 🔄 refresh, see your balance
- In Governance Panel: enter 0.001 BCH → click Lock & Mint
- You receive 100 GOV tokens
- Click YES buttons next to milestones to vote (each click uses tokens)
- Once >50% YES → click Release Funds → real Chipnet tx!
- On-chain vote counting via CashTokens burns
- Multi-sig release with CashScript
checkMultiSig - NFT milestone receipts for funders
- Backend indexer to track all project contracts