Monero on Internet Computer - Decentralized Mining and Wallet
Running Monero miner and wallet in a black-holed IC canister for decentralized cryptocurrency operations with complete privacy and autonomy

Introduction
What if you could run a Monero wallet and miner entirely on-chain, with no centralized servers, complete privacy, and autonomous operation? By leveraging the Internet Computer Protocol (ICP) and black-holed canisters, we can create truly decentralized Monero infrastructure that runs forever without human intervention.
This guide explores running Monero operations on ICP using monero-ts, creating an unstoppable privacy-focused cryptocurrency platform.
Why Monero on Internet Computer?
The Perfect Privacy Marriage
Monero provides:
- Private transactions by default
- Untraceable payments
- Fungible currency
- No transparent blockchain
Internet Computer provides:
- Decentralized compute
- Autonomous smart contracts (canisters)
- Black-hole capability (immutable, ownerless)
- Web-speed blockchain
Together they create:
- Fully autonomous Monero operations
- No server infrastructure needed
- Unstoppable wallet and mining services
- Complete privacy + decentralization
Project Overview
What We're Building
- Monero Wallet Canister - Manage XMR with Internet Identity
- Monero Mining Canister - Solo mining or pool mining on ICP
- Monero Explorer - Private transaction explorer
- Payment Gateway - Accept XMR payments for dApps
All running in black-holed canisters that can't be stopped or censored.
Architecture
┌─────────────────────────────────────────────┐
│ Internet Computer Protocol │
├─────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌─────────────────┐ │
│ │ Wallet │◄────►│ Mining │ │
│ │ Canister │ │ Canister │ │
│ └──────────────┘ └─────────────────┘ │
│ ▲ ▲ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ monero-ts Library │ │
│ │ (WebAssembly Monero Implementation)│ │
│ └──────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────┘
▲
│
▼
┌──────────────────────┐
│ Monero Network │
└──────────────────────┘
Prerequisites
- DFX SDK installed
- Node.js and npm
- Basic understanding of Monero
- Understanding of ICP canisters
- Familiarity with TypeScript
Setting Up the Project
Install DFX
sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
Create New Project
dfx new monero-on-ic
cd monero-on-ic
Install Dependencies
npm install monero-ts
npm install @dfinity/agent @dfinity/auth-client
Integrating monero-ts
Understanding monero-ts
monero-ts is a JavaScript/TypeScript library for Monero that works in browsers and Node.js. It provides:
- Full Monero wallet functionality
- Transaction creation and signing
- Daemon RPC interface
- WebAssembly-based cryptography
Basic Wallet Implementation
// src/monero-wallet.ts
import moneroTs from "monero-ts";
export class MoneroWallet {
private wallet: any;
async createWallet(password: string): Promise<string> {
// Create wallet in memory
this.wallet = await moneroTs.createWalletFull({
password: password,
networkType: "mainnet",
serverUri: "http://node.moneroworld.com:18089",
});
// Get mnemonic seed for backup
const mnemonic = await this.wallet.getMnemonic();
return mnemonic;
}
async restoreWallet(mnemonic: string, password: string): Promise<void> {
this.wallet = await moneroTs.createWalletFull({
password: password,
networkType: "mainnet",
serverUri: "http://node.moneroworld.com:18089",
mnemonic: mnemonic,
restoreHeight: 0, // or specific block height
});
await this.wallet.sync();
}
async getBalance(): Promise<{ confirmed: bigint; unconfirmed: bigint }> {
const balance = await this.wallet.getBalance();
const unlockedBalance = await this.wallet.getUnlockedBalance();
return {
confirmed: unlockedBalance,
unconfirmed: balance - unlockedBalance,
};
}
async getPrimaryAddress(): Promise<string> {
return await this.wallet.getPrimaryAddress();
}
async send(
address: string,
amount: bigint,
priority: number = 1
): Promise<string> {
const tx = await this.wallet.createTx({
accountIndex: 0,
address: address,
amount: amount,
priority: priority,
});
const hash = await tx.getHash();
return hash;
}
async getTransactions(): Promise<any[]> {
const txs = await this.wallet.getTxs();
return txs;
}
}
Canister Backend (Motoko)
// src/main.mo
import Blob "mo:base/Blob";
import Principal "mo:base/Principal";
import HashMap "mo:base/HashMap";
import Text "mo:base/Text";
import Nat "mo:base/Nat";
actor MoneroWallet {
// Store encrypted wallet data per user
private var wallets = HashMap.HashMap<Principal, Blob>(0, Principal.equal, Principal.hash);
// Create new wallet
public shared(msg) func createWallet(encryptedData: Blob) : async () {
wallets.put(msg.caller, encryptedData);
};
// Get wallet data
public shared(msg) func getWallet() : async ?Blob {
wallets.get(msg.caller)
};
// Store transaction history
public shared(msg) func saveTransaction(txData: Blob) : async () {
// Store transaction data
};
// Get transaction history
public shared(msg) func getTransactions() : async [Blob] {
// Return user's transactions
[]
};
}
Frontend Integration
// src/frontend/App.tsx
import React, { useState, useEffect } from "react";
import { AuthClient } from "@dfinity/auth-client";
import { MoneroWallet } from "./monero-wallet";
export default function App() {
const [authClient, setAuthClient] = useState<AuthClient | null>(null);
const [wallet, setWallet] = useState<MoneroWallet | null>(null);
const [balance, setBalance] = useState<string>("0");
const [address, setAddress] = useState<string>("");
useEffect(() => {
initAuth();
}, []);
async function initAuth() {
const client = await AuthClient.create();
setAuthClient(client);
if (await client.isAuthenticated()) {
await loadWallet();
}
}
async function login() {
await authClient?.login({
identityProvider: "https://identity.ic0.app",
onSuccess: async () => {
await loadWallet();
},
});
}
async function loadWallet() {
const moneroWallet = new MoneroWallet();
// Load encrypted wallet from canister
// Decrypt and initialize
setWallet(moneroWallet);
const bal = await moneroWallet.getBalance();
setBalance((Number(bal.confirmed) / 1e12).toString());
const addr = await moneroWallet.getPrimaryAddress();
setAddress(addr);
}
async function sendXMR(toAddress: string, amount: string) {
if (!wallet) return;
const amountAtomic = BigInt(parseFloat(amount) * 1e12);
const txHash = await wallet.send(toAddress, amountAtomic);
console.log("Transaction sent:", txHash);
}
return (
<div className="app">
<h1>Monero Wallet on IC</h1>
{!authClient?.isAuthenticated() ? (
<button onClick={login}>Login with Internet Identity</button>
) : (
<div>
<div className="wallet-info">
<h2>Your Wallet</h2>
<p>Address: {address}</p>
<p>Balance: {balance} XMR</p>
</div>
<div className="send-form">
<h3>Send XMR</h3>
{/* Send form here */}
</div>
</div>
)}
</div>
);
}
Monero Mining on IC
CPU Mining in Canister
While IC canisters aren't optimized for mining, you can implement solo mining for educational purposes or pool mining:
// src/miner.ts
import moneroTs from "monero-ts";
export class MoneroMiner {
private daemon: any;
private walletAddress: string;
constructor(walletAddress: string) {
this.walletAddress = walletAddress;
}
async connectDaemon() {
this.daemon = await moneroTs.connectToDaemonRpc(
"http://node.moneroworld.com:18089"
);
}
async startMining(threads: number = 1) {
await this.daemon.startMining({
address: this.walletAddress,
numThreads: threads,
backgroundMining: true,
});
}
async stopMining() {
await this.daemon.stopMining();
}
async getMiningStatus() {
const status = await this.daemon.getMiningStatus();
return {
active: status.isActive(),
speed: status.getSpeed(),
threads: status.getNumThreads(),
};
}
}
Pool Mining Integration
For practical mining, connect to a mining pool:
export class PoolMiner {
private poolConfig = {
pool: "pool.supportxmr.com:443",
wallet: "",
password: "x",
};
async mine(walletAddress: string) {
this.poolConfig.wallet = walletAddress;
// Use pool mining library
// Connect to pool and start mining
}
}
Black-Holing the Canister
To make your Monero infrastructure truly unstoppable, black-hole the canister:
# Deploy canister
dfx deploy monero-wallet
# Get canister ID
CANISTER_ID=$(dfx canister id monero-wallet)
# Black-hole (remove all controllers)
dfx canister update-settings $CANISTER_ID --set-controller $(dfx identity get-principal)
# Verify no controllers
dfx canister info $CANISTER_ID
Once black-holed, the canister runs autonomously forever.
Security Considerations
1. Wallet Encryption
Always encrypt wallet data before storing in canisters:
async function encryptWallet(walletData: string, password: string) {
// Use WebCrypto API
const enc = new TextEncoder();
const keyMaterial = await window.crypto.subtle.importKey(
"raw",
enc.encode(password),
"PBKDF2",
false,
["deriveBits", "deriveKey"]
);
// Derive key and encrypt
// Return encrypted blob
}
2. Mnemonic Seed Storage
Never store mnemonic seeds in canisters. Users should back up offline.
3. Transaction Signing
Sign transactions client-side, only broadcast through canister.
4. Rate Limiting
Implement rate limiting to prevent abuse:
private var requestCounts = HashMap.HashMap<Principal, Nat>(0, Principal.equal, Principal.hash);
public shared(msg) func send(recipient: Text, amount: Nat) : async Result.Result<Text, Text> {
let count = Option.get(requestCounts.get(msg.caller), 0);
if (count > 10) {
return #err("Rate limit exceeded");
};
requestCounts.put(msg.caller, count + 1);
// Process transaction
};
Use Cases
1. Anonymous Donations
Accept Monero donations for your dApp:
async function createDonationAddress() {
const wallet = new MoneroWallet();
const address = await wallet.getPrimaryAddress();
return address;
}
2. Private Payments
Accept private payments for services:
async function verifyPayment(txId: string, amount: bigint) {
const tx = await wallet.getTx(txId);
return tx.amount >= amount && tx.isConfirmed();
}
3. Decentralized Exchange
Build XMR to ICP token swaps.
4. Privacy-Preserving dApps
Use XMR for private transactions within your dApp ecosystem.
Deployment
Local Testing
# Start local replica
dfx start --background
# Deploy
dfx deploy
# Test
dfx canister call monero-wallet createWallet '(blob "encrypted_data")'
Mainnet Deployment
# Add cycles to wallet
dfx wallet balance
# Deploy to mainnet
dfx deploy --network ic
# Top up canisters with cycles
dfx canister deposit-cycles 1000000000000 monero-wallet --network ic
Performance Optimization
1. Wallet Sync Optimization
// Only sync recent blocks
await wallet.sync({
startHeight: lastSyncedBlock,
});
2. Caching
Cache blockchain data to reduce RPC calls:
private var blockCache = HashMap.HashMap<Nat, Blob>(0, Nat.equal, Hash.hash);
3. Batching
Batch multiple operations:
async function batchGetBalances(addresses: string[]) {
return Promise.all(addresses.map((addr) => getBalance(addr)));
}
Monitoring and Maintenance
Health Checks
public query func getStatus() : async {
online: Bool;
lastSync: Nat;
cyclesBalance: Nat;
} {
{
online = true;
lastSync = lastSyncTime;
cyclesBalance = Cycles.balance();
}
};
Automatic Cycle Top-Up
Use cycles management canisters to auto-top-up.
Links
- dApp: Coming soon
- Source Code: Coming soon
- Live Demo: Coming soon
Resources
- monero-ts - TypeScript Monero library
- monero-ts Vite Template - Sample project
- Monero Documentation
- ICP Developer Docs
- Internet Identity
- Monero RPC Documentation
Challenges and Solutions
Challenge 1: WebAssembly in Canisters
Problem: monero-ts relies on WebAssembly Solution: Use frontend canister with WASM support, backend for storage only
Challenge 2: Daemon Connection
Problem: Need to connect to Monero daemon Solution: Use public nodes or run own node, use HTTP outcalls from canister
Challenge 3: Transaction Privacy
Problem: Storing transaction data Solution: Store only encrypted metadata, user controls decryption
Challenge 4: Mining Economics
Problem: IC compute cycles cost Solution: Focus on pool mining, or use for educational purposes only
Future Enhancements
- Atomic Swaps - XMR ↔ ICP token swaps
- Multi-Signature Wallets - Shared XMR wallets with IC governance
- Payment Channels - Lightning-style payment channels for XMR
- DeFi Integration - Use XMR as collateral for ICP DeFi
- Mobile App - React Native app with IC integration
Conclusion
Running Monero on the Internet Computer combines the best of both privacy-focused cryptocurrency and decentralized computing. By leveraging monero-ts and IC canisters, you can build truly unstoppable, privacy-preserving financial applications.
The combination of Monero's untraceable transactions and IC's autonomous smart contracts creates a powerful platform for the next generation of private, decentralized finance.
Start experimenting with monero-ts today and build the future of private, decentralized money.
Disclaimer: This is for educational purposes. Always comply with local regulations regarding cryptocurrency. Never store significant funds in experimental dApps. Mining profitability on IC may be negative due to compute costs.