A simple, educational implementation of fungible token minting and transfers on the BSV blockchain using overlays.
New to this workshop? → Read BSV_DESKTOP_SETUP.md for BSV Desktop Wallet setup!
Prerequisites:
- BSV Desktop Wallet running and unlocked (get it at https://yours.org/)
- BSV funds for transaction fees (~$0.01 per transaction)
- MongoDB and MySQL running
Quick Start:
- Terminal 1:
npm run dev(start overlay server) - Terminal 2:
npm run mint(create real tokens on mainnet) - Terminal 3:
npm run wallet(view/transfer tokens)
This workshop demonstrates three core components:
- Overlay Service - Validates and tracks token transactions on the blockchain
- Mint App - Creates new fungible tokens
- Wallet App - Transfers tokens and views balances
- Simple & Clear: Minimal code, maximum understanding
- Lean Management: No complex abstractions, direct BSV SDK usage
- Educational: Well-commented code showing token protocols
- Production-Ready Patterns: Real overlay architecture you can build on
tokenisation-workshop/
├── src/
│ ├── index.ts # Overlay server entry point
│ ├── services/
│ │ └── token/
│ │ ├── TokenTopicManager.ts # Validates token transactions
│ │ ├── TokenLookupService.ts # Query token data
│ │ └── TokenStorageManager.ts # MongoDB storage
│ └── apps/
│ ├── mint.ts # Token minting CLI
│ └── wallet.ts # Token wallet CLI
├── package.json
├── tsconfig.json
└── .env # Configuration (create from .env.example)
Tokens are represented as OP_RETURN outputs with this format:
OP_0 OP_RETURN <protocol> <tokenId> <amount> [<metadata>]
| Field | Type | Size | Description |
|---|---|---|---|
| protocol | UTF-8 string | Variable | Always 'TOKEN' |
| tokenId | Hex string | 32 bytes | Unique token identifier |
| amount | Integer | 8 bytes | Token units (little-endian) |
| metadata | JSON | Variable | Optional token info (name, symbol, etc.) |
{
"name": "Workshop Token",
"symbol": "WST",
"decimals": 6,
"description": "Example fungible token",
"totalSupply": 1000000
}- Node.js 18+
- MongoDB (for token storage)
- MySQL (for overlay engine)
- BSV Desktop Wallet (download from https://yours.org/)
- BSV funds for transaction fees
# Install dependencies
npm install
# Create environment configuration
cp .env.example .env
# Edit .env with your settings
nano .envEdit .env:
# Your overlay node name
NODE_NAME=tokenworkshop
# BSV private key (hex) for the overlay server
SERVER_PRIVATE_KEY=your_32_byte_hex_key
# Where your overlay is hosted
HOSTING_URL=http://localhost:8080
# Database connections
MONGO_URL=mongodb://localhost:27017/tokenworkshop
KNEX_URL=mysql://root:password@localhost:3306/tokenworkshop
# BSV Desktop Wallet Configuration (REQUIRED for minting and transfers)
WAB_SERVER_URL=https://wab.babbage.systems
WALLET_STORAGE_URL=https://storage.babbage.systems
MESSAGE_BOX_URL=https://messagebox.babbage.systems
IDENTITY_KEY=your_identity_key_from_wallet
# Network (mainnet)
NETWORK=main# Start MongoDB
docker run -d -p 27017:27017 --name mongo mongo:latest
# Start MySQL
docker run -d -p 3306:3306 --name mysql \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=tokenworkshop \
mysql:latestnpm run devThis starts the overlay node on port 8080 with:
- Token Topic Manager (
tm_tokens) - Validates token transactions - Token Lookup Service (
ls_tokens) - Queries token data
Important: Make sure BSV Desktop Wallet is running and unlocked!
In a separate terminal:
npm run mintFollow the interactive prompts:
Token Name: Workshop Token
Token Symbol: WST
Decimals (default 0): 6
Total Supply: 1000000
Description (optional): Example token for workshop
The mint app will:
- Connect to your BSV Desktop Wallet
- Generate a unique 32-byte token ID
- Create a token output with metadata
- Request your approval in BSV Desktop Wallet
- Sign and broadcast the transaction to BSV mainnet
- Display the transaction ID on WhatsOnChain
This creates REAL tokens on the BSV blockchain!
Important: Make sure BSV Desktop Wallet is running and unlocked!
npm run walletThe wallet will:
- Connect to your BSV Desktop Wallet
- Display interactive menu
Menu options:
- View Balances - Shows all tokens indexed by your overlay
- Transfer Tokens - Send tokens to another address (requires wallet approval)
- Exit
Example transfer:
Token ID: a1b2c3d4e5f6...
Amount: 50000
Recipient Address: 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
The transfer will:
- Create the token transfer transaction
- Request your approval in BSV Desktop Wallet
- Sign and broadcast to BSV mainnet
- Show the transaction on WhatsOnChain
The lookup service supports these query types:
{
type: 'balance',
tokenId: 'a1b2c3d4...'
}Returns:
{
type: 'output-list',
outputs: [
{
txid: '...',
outputIndex: 0,
amount: 1000000,
tokenId: '...',
name: 'Workshop Token',
symbol: 'WST',
decimals: 6
}
]
}{
type: 'balances'
}Returns list of all token balances grouped by tokenId.
{
type: 'history',
tokenId: 'a1b2c3d4...',
limit: 50
}{
type: 'utxos',
tokenId: 'a1b2c3d4...'
}Returns unspent token outputs for spending.
This workshop demonstrates key BSV SDK patterns:
import { Transaction, Script, Utils } from '@bsv/sdk'
const tx = new Transaction()
tx.addOutput({
satoshis: 0,
lockingScript: tokenScript
})import { PushDrop } from '@bsv/sdk'
const result = PushDrop.decode({
script: output.lockingScript.toHex(),
fieldFormat: 'buffer'
})
const protocol = Utils.toUTF8(result.fields[0])
const tokenId = Utils.toHex(result.fields[1])const tx = Transaction.fromBEEF(beef)import { PrivateKey } from '@bsv/sdk'
const privateKey = PrivateKey.fromString(hex, 'hex')
const publicKey = privateKey.toPublicKey()
const address = publicKey.toAddress()Validates transactions before admission to the overlay:
class TokenTopicManager implements TopicManager {
async identifyAdmissibleOutputs(
beef: number[],
previousCoins: number[]
): Promise<AdmittanceInstructions> {
// Parse transaction
// Validate token format
// Return valid output indices
}
}Handles queries and tracks token state:
class TokenLookupService implements LookupService {
async outputAdmittedByTopic(payload): Promise<void> {
// Store new token output
}
async outputSpent(payload): Promise<void> {
// Mark token as spent
}
async lookup(question): Promise<LookupFormula> {
// Handle balance/history queries
}
}Manages MongoDB operations:
class TokenStorageManager {
async storeToken(txid, outputIndex, tokenId, amount, metadata)
async markAsSpent(txid, outputIndex)
async getBalance(tokenId)
async getAllBalances()
}This workshop uses REAL BSV mainnet! Your tokens are permanent on the blockchain.
- ✅ Real BSV Desktop Wallet integration
- ✅ Actual mainnet transactions
- ✅ Proper transaction signing and broadcasting
- ✅ Overlay validation and indexing
- ✅ Token protocol following BRC-48 (PushDrop)
- ⚡ Add authentication/authorization on overlay API
- ⚡ Implement rate limiting
- ⚡ Validate all user inputs server-side
- ⚡ Add audit logging
- ⚡ Handle chain reorganizations
- ⚡ Add transaction history tracking
- ⚡ Implement proper fee estimation
- ⚡ Add UTXO consolidation
- ⚡ Implement retry logic for network failures
- ⚡ Monitor transaction confirmation status
- ⚡ Handle double-spend detection
- ⚡ Add database indexing for faster queries
- ⚡ Implement caching layer
- ⚡ Use connection pooling
- ⚡ Add monitoring/logging (Prometheus, Grafana)
- ⚡ Add access controls (who can mint)
- ⚡ Implement token burning
- ⚡ Add supply management
- ⚡ Multi-signature support
- ⚡ Token metadata updates
Ideas for enhancement:
- NFTs - Add unique token support with metadata
- Token Exchange - Build atomic swap functionality
- Access Control - Add owner-only minting
- Dividends - Distribute tokens to holders
- Governance - Voting with token weights
- DeFi - Lending, staking, yield farming
Error: "No wallet available over any communication substrate"
- Make sure BSV Desktop Wallet is running and unlocked
- Verify
WAB_SERVER_URLin.envis correct - Check that your wallet has BSV for transaction fees
- Try restarting BSV Desktop Wallet
Error: "Failed to connect to BSV Desktop Wallet"
- Ensure BSV Desktop Wallet is open and not minimized
- Unlock your wallet with your password
- Check network connectivity
- Verify the WAB server URLs in
.env
- Check MongoDB is running:
docker ps - Check MySQL is running:
docker ps - Verify
.envconfiguration - Check port 8080 is available
- Verify BSV Desktop Wallet is running and unlocked
- Check you have BSV funds for fees (~500-1000 satoshis)
- Ensure overlay server is running
- Check
WAB_SERVER_URLin.env
- Wait for overlay to index transactions
- Check MongoDB connection
- Verify token transactions were broadcast successfully
- Check overlay logs for errors
- Confirm transactions on WhatsOnChain
MIT
This is an educational workshop. Feel free to:
- Report issues
- Submit improvements
- Create tutorials
- Build on this foundation
Workshop Goals Achieved: ✅ Simple, clear code ✅ Good use of BSV SDK ✅ Proper overlay patterns ✅ Lean management ✅ Production-ready architecture ✅ Educational value
Happy tokenizing! 🚀