A secure, production-ready Bitcoin paywall implementation in Go, designed to help creative workers join the Bitcoin economy by controlling their own content distribution platforms with minimal barriers to entry.
go get github.com/opd-ai/paywall
package main
import (
"log"
"net/http"
"time"
"github.com/opd-ai/paywall"
)
func main() {
// Initialize paywall with minimal config
pw, err := paywall.NewPaywall(paywall.Config{
PriceInBTC: 0.001, // 0.001 BTC
TestNet: true, // Use testnet
Store: paywall.NewMemoryStore(), // In-memory storage
PaymentTimeout: time.Hour * 24, // 24-hour payment window
})
// Call close when your program shuts down to terminate the payment check routine co
defer pw.Close()
if err != nil {
log.Fatal(err)
}
// Protected content handler
protected := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Protected content"))
})
// Apply paywall middleware
http.Handle("/protected", pw.Middleware(protected))
log.Fatal(http.ListenAndServe(":8000", nil))
}
type Config struct {
PriceInBTC float64 // Price in Bitcoin
PriceInXMR float64 // Price in Monero (optional)
TestNet bool // Use testnet networks
Store PaymentStore // Storage backend
PaymentTimeout time.Duration // Payment expiration time
MinConfirmations int // Required blockchain confirmations
XMRUser string // Monero wallet RPC username (optional)
XMRPassword string // Monero wallet RPC password (optional)
XMRRPC string // Monero RPC endpoint URL (optional)
}
Bitcoin-Only vs Multi-Currency Configuration:
PriceInBTC is required. XMR fields (XMRUser, XMRPassword, XMRRPC, PriceInXMR) are optional and can be omitted.NewMemoryStore(): In-memory payment tracking (default)NewFileStore(): Filesystem-based persistent storageUser-friendly wallet backup with 12 or 24-word phrases:
// Generate new mnemonic (24 words recommended)
mnemonic, err := wallet.GenerateMnemonic(wallet.Mnemonic24Words)
// Example: "abandon ability able about above absent absorb abstract..."
// Create wallet from mnemonic
wallet, err := wallet.NewBTCHDWalletFromMnemonic(
mnemonic,
"", // Optional passphrase for extra security
true, // Testnet
1, // Min confirmations
)
// Restore wallet from backed-up mnemonic
seed, err := wallet.ImportFromMnemonic(mnemonic, "")
wallet, err := wallet.NewBTCHDWallet(seed[:32], testnet, 1)
// Validate user-entered mnemonic
if !wallet.ValidateMnemonic(userInput) {
fmt.Println("Invalid mnemonic phrase")
}
Mnemonic Backup Best Practices:
// Generate new wallet encryption key
key, err := wallet.GenerateEncryptionKey()
// Configure wallet storage
config := wallet.StorageConfig{
DataDir: "./paywallet",
EncryptionKey: key,
}
// Save Bitcoin wallet (type assertion required)
btcWallet := pw.HDWallets[wallet.Bitcoin].(*wallet.BTCHDWallet)
err = btcWallet.SaveToFile(config)
// Load wallet from file
loadedWallet, err := wallet.LoadFromFile(config)
Note on Wallet Recovery: You can now use BIP39 mnemonics for wallet recovery! The mnemonic provides full wallet recovery including the seed. However, the nextIndex counter (tracking which addresses have been used) is not stored in the mnemonic. To preserve address history, back up both the mnemonic AND the encrypted wallet files. If you lose the wallet file but have the mnemonic, addresses will regenerate from the beginning, which may cause address reuse if previous addresses received payments.
The paywall now supports Monero multisig wallets for escrow and multi-party payment scenarios. Monero multisig setup is a multi-step process requiring coordination between all participants.
2-of-3 Multisig Setup Example:
// Create wallets for all three participants
wallet1, _ := wallet.NewMoneroWallet(config1, 1)
wallet2, _ := wallet.NewMoneroWallet(config2, 1)
wallet3, _ := wallet.NewMoneroWallet(config3, 1)
// Step 1: Each participant prepares multisig
info1, _ := wallet1.PrepareMultisig(2) // threshold = 2
info2, _ := wallet2.PrepareMultisig(2)
info3, _ := wallet3.PrepareMultisig(2)
// Step 2: Each participant makes multisig with others' info
round2Info1, addr1, _ := wallet1.MakeMultisig([]string{info2, info3}, 2)
round2Info2, addr2, _ := wallet2.MakeMultisig([]string{info1, info3}, 2)
round2Info3, addr3, _ := wallet3.MakeMultisig([]string{info1, info2}, 2)
// Step 3: Finalize multisig (required for M-of-N where M < N)
wallet1.FinalizeMultisig([]string{round2Info2, round2Info3})
wallet2.FinalizeMultisig([]string{round2Info1, round2Info3})
wallet3.FinalizeMultisig([]string{round2Info1, round2Info2})
// Now wallets are ready for multisig payments
// Use with EscrowManager for marketplace/subscription scenarios
Using Monero Multisig with Escrow:
// After multisig setup, create escrow payment
escrowMgr := paywall.NewEscrowManager(pw)
payment, _ := escrowMgr.CreateEscrow(
0.1, // 0.1 XMR
wallet.Monero, // Use Monero multisig
buyerPubKey,
sellerPubKey,
arbiterPubKey,
2, // 2-of-3 signatures required
)
// The payment uses the Monero multisig address
// Transaction signing requires coordination via ExportMultisigInfo/ImportMultisigInfo
Important Notes:
// Memory Store
store := paywall.NewMemoryStore()
// File Store (simple)
store := paywall.NewFileStore("./payments")
// File Store with encryption (recommended for production)
encryptionKey, err := wallet.GenerateEncryptionKey()
if err != nil {
log.Fatal(err)
}
store, err := paywall.NewFileStoreWithConfig(paywall.FileStoreConfig{
DataDir: "/var/lib/paywall/data",
EncryptionKey: encryptionKey, // Optional: enables AES-256 encryption
})
if err != nil {
log.Fatal(err)
}
Perfect for:
Contributions are welcome! Please feel free to submit a Pull Request.
Re: support for other cryptocurrency, we will consider other currencies, but we consider Monero to be the only good cryptocurrency.
This is because Monero is the only good cryptocurrency.
Bitcoin is supported out of expediency, Ethereum may also be worth supporting. Weβre not going to focus on shitcoins.
If you find this project useful, consider supporting the developer:
Monero Address: 43H3Uqnc9rfEsJjUXZYmam45MbtWmREFSANAWY5hijY4aht8cqYaT2BCNhfBhua5XwNdx9Tb6BEdt4tjUHJDwNW5H7mTiwe
Bitcoin Address: bc1qew5kx0srtp8c4hlpw8ax0gllhnpsnp9ylthpas
MIT License - see LICENSE file for details
Created and maintained by the OPD AI team.