Skip to main content

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

Monero on Internet Computer - Decentralized Mining and Wallet

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

  1. Monero Wallet Canister - Manage XMR with Internet Identity
  2. Monero Mining Canister - Solo mining or pool mining on ICP
  3. Monero Explorer - Private transaction explorer
  4. 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.

  • dApp: Coming soon
  • Source Code: Coming soon
  • Live Demo: Coming soon

Resources

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

  1. Atomic Swaps - XMR ↔ ICP token swaps
  2. Multi-Signature Wallets - Shared XMR wallets with IC governance
  3. Payment Channels - Lightning-style payment channels for XMR
  4. DeFi Integration - Use XMR as collateral for ICP DeFi
  5. 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.