Gun.js Blockchain Extension

A powerful Gun.js plugin that extends its capabilities by adding advanced blockchain and cryptographic features to create more secure and private decentralized applications

Features

🔧 Gun.js Extensions

Base Methods
  • GunEth.verifySignature(address, signature, message) - Verify an Ethereum signature
  • GunEth.createSignature(GunEth.MESSAGE_TO_SIGN) - Create a signature using connected wallet
  • GunEth.ethToGunAccount() - Convert Ethereum account to Gun
  • GunEth.gunToEthAccount(gunPrivateKey) - Convert Gun account to Ethereum
Key Management
  • GunEth.createAndStoreEncryptedPair(address, signature) - Create and store encrypted key pairs
  • GunEth.getAndDecryptPair(address, signature) - Retrieve and decrypt key pairs
Stealth Chain
  • GunEth.StealthChain - Class for managing stealth transactions
  • GunEth.createStealthTransaction(provider, chainId, receiverViewingKey, receiverSpendingKey) - Create a complete stealth transaction
  • GunEth.recoverStealthFunds(provider, chainId, stealthAddress, senderPublicKey, signature, spendingPublicKey) - Recover funds from a stealth address
  • GunEth.getStealthPayments(provider, chainId, viewingKey, options) - Retrieve stealth payments
  • GunEth.announcePaymentOnChain(provider, chainId, stealthAddress, senderEphemeralKey, receiverViewingKey, receiverSpendingKey) - Announce a stealth transaction directly on the blockchain

Stealth Transaction Example


// Esempio base di transazione stealth
const provider = new ethers.JsonRpcProvider("RPC_URL");
const chainId = "polygon"; // o altra chain supportata

// Crea una transazione stealth
const result = await GunEth.createStealthTransaction(
  provider,
  chainId,
  receiverViewingKey,
  receiverSpendingKey
);

console.log("Stealth Address:", result.stealthInfo.stealthAddress);
console.log("Transaction Hash:", result.transaction.hash);

// Recupera i pagamenti
const payments = await GunEth.getStealthPayments(
  provider,
  chainId,
  viewingKey
);

// Recupera i fondi
const recoveryTx = await GunEth.recoverStealthFunds(
  provider,
  chainId,
  stealthAddress,
  senderPublicKey,
  signature,
  spendingPublicKey
);

// Esempio avanzato con StealthChain
const stealthChain = new GunEth.StealthChain(provider, chainId);

// Verify chain support
const isSupported = await stealthChain.isOnSupportedChain();
if (!isSupported) {
  await stealthChain.requestChainSwitch();
}

// Generate stealth address
const stealthInfo = await stealthChain.generateStealthAddress(
  receiverViewingKey,
  receiverSpendingKey
);

// Annuncia il pagamento sulla blockchain
await stealthChain.announcePaymentOnChain(
  provider,
  chainId,
  stealthInfo.stealthAddress,
  stealthInfo.senderEphemeralKey,
  receiverViewingKey,
  receiverSpendingKey
);

// Monitora nuovi annunci
stealthChain.listenToNewAnnouncements((announcement) => {
  console.log("Nuovo annuncio:", announcement);
});

⛓️ Smart Contracts

StealthChain Contract

Contract for managing stealth transactions on the blockchain.

View Contract
  • Main Functions:
    • announcePayment(bytes senderPublicKey, bytes spendingPublicKey, address stealthAddress) - Announce a new stealth payment
    • getAnnouncementsInRange(uint256 fromIndex, uint256 toIndex) - Retrieve announcements in a range
    • getAnnouncementsCount() - Get total number of announcements
    • devFee() - Get current fee for announcements
  • Events:
    • StealthPaymentAnnounced(bytes senderPublicKey, bytes spendingPublicKey, address stealthAddress, uint256 timestamp)
BubbleRegistry Contract

Contract for managing Bubbles on the blockchain.

View Contract
  • Main Functions:
    • createBubble(string name, bool isPrivate) - Create a new bubble
    • getBubble(uint256 bubbleId) - Get bubble details
    • getUserBubbles(address user) - Get all user's bubbles
    • updateBubblePrivacy(uint256 bubbleId, bool isPrivate) - Update bubble privacy
  • Events:
    • BubbleCreated(uint256 bubbleId, address owner, string name, bool isPrivate)
    • BubblePrivacyUpdated(uint256 bubbleId, bool isPrivate)
Contract Addresses

The contracts are currently deployed on Polygon Mainnet:

View Addresses

// Polygon Mainnet
{
  StealthAnnouncer: "0xD0CDbD17E4f2DDCE27B51721095048302768434f",
  BubbleRegistry: "0xc70DC231B9690D9dA988f6D4E518356eE9e45cd9"
}

To interact with the contracts:

  1. StealthAnnouncer:
    • Fee: Requires a small fee in MATIC for each announcement
    • Gas: Operations require gas on Polygon network
    • Verification: Announcements are verifiable on-chain
  2. BubbleRegistry:
    • Ownership: Bubbles are associated with creator's address
    • Privacy: Supports public and private bubbles
    • Permissions: Only owner can modify settings
Contract Interaction

// Import addresses and ABIs
import addresses from "./contracts/addresses.js";
import stealthAnnouncer_abi from "./contracts/stealthChain/stealthAnnouncer_abi.json";
import bubbleRegistry_abi from "./contracts/bubbleChain/bubbleRegistry_abi.json";

// Initialize contracts
const stealthAnnouncer = new ethers.Contract(
  addresses.polygon.StealthAnnouncer,
  stealthAnnouncer_abi,
  provider
);

const bubbleRegistry = new ethers.Contract(
  addresses.polygon.BubbleRegistry,
  bubbleRegistry_abi,
  provider
);

// StealthAnnouncer Example
const fee = await stealthAnnouncer.devFee();
const tx = await stealthAnnouncer.announcePayment(
  senderPublicKey,
  spendingPublicKey,
  stealthAddress,
  { value: fee }
);

// BubbleRegistry Example
const bubble = await bubbleRegistry.createBubble(
  "My Bubble",
  true,  // private
  { gasLimit: 500000 }  // recommended gas limit
);

// Verify bubble properties
const owner = await bubbleRegistry.ownerOf(bubbleId);
const isPrivate = await bubbleRegistry.isPrivate(bubbleId);

🔐 Gun-Ethereum Integration

Understanding Gun-Ethereum Integration

What is Gun-Ethereum Integration?

Gun-Ethereum integration enables seamless interaction between Gun's decentralized database and Ethereum's blockchain. This integration allows you to use Ethereum wallets for authentication while leveraging Gun's real-time capabilities.

Key Components
  • Ethereum Wallet: Used for authentication and signing messages
  • Gun SEA: Gun's Security, Encryption, and Authorization system
  • Conversion Layer: Translates between Ethereum and Gun authentication systems
How it Works
  1. User connects their Ethereum wallet (MetaMask or custom configuration)
  2. Wallet signs a specific message to prove ownership
  3. Signature is used to generate Gun SEA compatible keypairs
  4. Generated keypairs enable encrypted data storage in Gun
  5. Data can be accessed using either Ethereum or Gun credentials
Security Features
  • End-to-end encryption of stored data
  • Cryptographic proof of ownership
  • No private key exposure
  • Secure key derivation process

Authentication Example

Example

// Initialize Gun-ETH
import { GunEth } from 'gun-eth';
import Gun from 'gun';
import { ethers } from 'ethers';

// Configure Gun with peers
const gun = Gun({
    peers: ['http://localhost:8765/gun']
});

// Initialize GunEth
const gunEth = await GunEth.init('localhost');

// Signer Configuration Options:

// 1. Manual Configuration (Production)
if (process.env.RPC_URL && process.env.PRIVATE_KEY) {
    await gunEth.setSigner(process.env.RPC_URL, process.env.PRIVATE_KEY);
}

// 2. MetaMask Integration (Development)
else {
    // SignerManager getting automatically MetaMask se disponibile
    const signer = await gunEth.getSigner();
    if (!signer) {
        throw new Error("No valid Ethereum provider found");
    }
}

// Handle errors
else {
    throw new Error("No valid Ethereum provider found");
}

// Convert an Ethereum account to a Gun account
import { GunEth } from 'gun-eth';

// Create signature with Ethereum wallet
const signature = await GunEth.createSignature(GunEth.MESSAGE_TO_SIGN);

// Convert to Gun SEA keypair
const gunAccount = await GunEth.ethToGunAccount(signature);

// The account contains:
console.log({
  pub: gunAccount.pub,    // Gun public key
  priv: gunAccount.priv,  // Gun private key
  epub: gunAccount.epub,  // Encryption public key
  epriv: gunAccount.epriv // Encryption private key
});

// Option 1: Using existing Gun credentials
const gunUser = gun.user();
if (gunUser.is) {
  // Use existing Gun credentials
  const account = await gunToEthAccount(gunUser._.sea);
}

// Option 2: Using Ethereum signature
const gunKeyPair = await SEA.pair();
const signature = await createSignature(MESSAGE_TO_SIGN);
const account = await gunToEthAccount(gunKeyPair, signature);

// Returns
{
  pub: gunKeyPair.pub,                // Gun public key
  internalWalletAddress: string,      // Internal wallet address
  internalWalletPk: string,          // Internal wallet private key
  pair: gunKeyPair,                  // Original Gun keypair
  v_pair: SEA.pair(),                // Viewing keypair
  s_pair: SEA.pair(),                // Spending keypair
  viewingPublicKey: string,          // Viewing public key (v_pair.epub)
  spendingPublicKey: string,         // Spending public key (s_pair.epub)
  env_pair: string,                  // Encrypted original pair
  env_v_pair: string,                // Encrypted viewing pair
  env_s_pair: string                 // Encrypted spending pair
}

// Complete usage example
const signature = await createSignature(MESSAGE_TO_SIGN);
const gunAccount = await ethToGunAccount(signature);

// Save encrypted data
await gun.user(gunAccount.pub).get('myData').put({
    secret: "Data encrypted with Gun keys"
});

// Retrieve encrypted data
const data = await gun.user(gunAccount.pub).get('myData').then();

// Convert back to Ethereum if needed
const ethAccount = await gunToEthAccount(gunAccount);
1

Connect Wallet

Connect your Ethereum wallet and sign the authentication message

2

Convert Account

Convert your Ethereum account to a Gun account using ethToGunAccount

3

Use Gun Features

Use all Gun features with your converted account

4

Convert Back

If needed, convert back to Ethereum account using gunToEthAccount

Advanced Key Management

Gun-ETH provides a complete system for secure key management with support for multiple pairs and advanced encryption.

Key Structure
  • Main Pair: Used for authentication and general management
  • Viewing Pair: For read-only access to encrypted data
  • Spending Pair: For operations requiring authorization

// Generate password from Ethereum signature
const signature = await wallet.signMessage(MESSAGE_TO_SIGN);
const password = generatePassword(signature);

// Password is a keccak256 hash of the signature
console.log(password); // 0x...

// Verify signature
const isValid = await verifySignature(
  address,    // Ethereum address
  signature,  // Signature to verify
  MESSAGE_TO_SIGN  // Original message
);

// Complete structure returned by gunToEthAccount
{
  "pub": "gun-public-key",
  "internalWalletAddress": "0x...",
  "internalWalletPk": "0x...",
  "pair": {
    "pub": "...",
    "priv": "...",
    "epub": "...",
    "epriv": "..."
  },
  "v_pair": {
    "pub": "...",
    "priv": "...",
    "epub": "...",
    "epriv": "..."
  },
  "s_pair": {
    "pub": "...",
    "priv": "...",
    "epub": "...",
    "epriv": "..."
  },
  "viewingPublicKey": "...",
  "spendingPublicKey": "...",
  "env_pair": "encrypted-data",
  "env_v_pair": "encrypted-data",
  "env_s_pair": "encrypted-data"
}

// Encrypt a key pair
const password = generatePassword(signature);
const encryptedPair = await encrypt(pair, password);

// Decrypt a key pair
const decryptedPair = await decrypt(encryptedPair, {
  epriv: password,
  epub: password
});

// Multiple key pair management
const pairs = await ethToGunAccount();
await gun.get("gun-eth")
  .get("users")
  .get(address)
  .put({
    pair: pairs.env_pair,      // Encrypted main pair
    v_pair: pairs.env_v_pair,  // Encrypted viewing pair
    s_pair: pairs.env_s_pair,  // Encrypted spending pair
    publicKeys: pairs.publicKeys
  });
Security Features
  • Password Generation: Secure derivation from Ethereum signature
  • Signature Verification: Cryptographic identity validation
  • Multiple Encryption: Separate protection for each key pair
  • Viewing/Spending Management: Access privilege separation

Gun-Ethereum Account Conversion

Gun-ETH provides robust methods for converting between Gun and Ethereum accounts with enhanced security features.

1. Ethereum to Gun (ethToGunAccount)

const account = await ethToGunAccount();

// Returns
{
    pair: SEA.pair(),          // Main Gun keypair
    v_pair: SEA.pair(),        // Viewing keypair
    s_pair: SEA.pair(),        // Spending keypair
    ethAddress: string,        // Ethereum address
    ethPrivateKey: string,     // Ethereum private key
    env_pair: string,          // Encrypted main pair
    env_v_pair: string,        // Encrypted viewing pair
    env_s_pair: string         // Encrypted spending pair
}
2. Gun to Ethereum (gunToEthAccount)

// Option 1: Using existing Gun credentials
const gunUser = gun.user();
if (gunUser.is) {
  // Use existing Gun credentials
  const account = await gunToEthAccount(gunUser._.sea);
}

// Option 2: Using Ethereum signature
const gunKeyPair = await SEA.pair();
const signature = await createSignature(MESSAGE_TO_SIGN);
const account = await gunToEthAccount(gunKeyPair, signature);

// Returns
{
  pub: gunKeyPair.pub,                // Gun public key
  internalWalletAddress: string,      // Internal wallet address
  internalWalletPk: string,          // Internal wallet private key
  pair: gunKeyPair,                  // Original Gun keypair
  v_pair: SEA.pair(),                // Viewing keypair
  s_pair: SEA.pair(),                // Spending keypair
  viewingPublicKey: string,          // Viewing public key (v_pair.epub)
  spendingPublicKey: string,         // Spending public key (s_pair.epub)
  env_pair: string,                  // Encrypted original pair
  env_v_pair: string,                // Encrypted viewing pair
  env_s_pair: string                 // Encrypted spending pair
}
3. Key Management

// Store encrypted keypair
await gun.createAndStoreEncryptedPair(address);

// Retrieve and decrypt keypair
const signature = await createSignature(MESSAGE_TO_SIGN);
const pair = await gun.getAndDecryptPair(address, signature);

// Decrypt pair with password
const decryptedPair = await decryptPair(encryptedPair, password);

// Create signature
const signature = await createSignature(MESSAGE_TO_SIGN);
Security Features
  • Multiple Keypairs: Separate pairs for main, viewing, and spending operations
  • Encrypted Storage: All sensitive data is encrypted before storage
  • Message Signing: Uses Ethereum signatures for authentication
  • Automatic Retry: Built-in retry mechanism for failed operations
  • Password Generation: Secure password generation from signatures

🔒 StealthChain

StealthChain può essere utilizzato in due modalità:

1. Modalità Off-chain


// Inizializzazione senza provider
const stealthChain = new StealthChain();

// Operazioni base disponibili
const stealthInfo = await stealthChain.generateStealthAddress(
  receiverViewingKey,
  receiverSpendingKey
);

const announcement = stealthChain.createStealthAnnouncement(
  stealthInfo.stealthAddress,
  stealthInfo.senderEphemeralPublicKey,
  receiverViewingKey,
  receiverSpendingKey
);

2. Modalità On-chain


// Inizializzazione con provider
const provider = new ethers.JsonRpcProvider("RPC_URL");
const stealthChain = new StealthChain(provider, "polygon");

// Verifica modalità
if (stealthChain.isOnChainEnabled()) {
  // Annuncia pagamento on-chain
  await stealthChain.announcePaymentOnChain(
    stealthInfo.stealthAddress,
    stealthInfo.senderEphemeralKey,
    receiverViewingKey,
    receiverSpendingKey
  );

  // Ottieni fee corrente
  const fee = await stealthChain.getCurrentFee();

  // Monitora nuovi annunci
  stealthChain.listenToNewAnnouncements((announcement) => {
    console.log("Nuovo annuncio:", announcement);
  });
}

Funzionalità Disponibili

  • generateStealthAddress: Genera un nuovo indirizzo stealth
  • deriveStealthAddress: Deriva un indirizzo stealth dai parametri
  • createStealthAnnouncement: Crea un annuncio di pagamento
  • createRecoveryData: Prepara i dati per il recupero fondi
  • announcePaymentOnChain: Annuncia pagamento sulla blockchain
  • getAnnouncementsInRange: Recupera annunci in un range
  • getTotalAnnouncements: Ottiene numero totale annunci
  • getCurrentFee: Recupera fee corrente
  • listenToNewAnnouncements: Ascolta nuovi annunci
  • isStealthAddressAnnounced: Verifica se indirizzo è stato annunciato
  • getExplorerUrl: Ottiene URL explorer per transazione

Encrypted Bubbles

Encrypted Bubbles provide secure and decentralized storage with end-to-end encryption. Two provider implementations are available:

Provider Types
1. GUN Provider
  • Storage: Stores both data and metadata in GUN's decentralized database
  • Best for: Fully decentralized applications where all data needs to be replicated across peers
  • Features:
    • Complete P2P replication
    • Real-time synchronization
    • No filesystem dependencies
2. Hybrid Provider
  • Storage: Stores files in local filesystem, metadata in GUN
  • Best for: Applications that need to handle large files or require filesystem access
  • Features:
    • Better performance with large files
    • Direct filesystem access
    • Hybrid storage model (files local, metadata distributed)
Example: GUN Provider

// Initialize GUN provider
const gunProvider = new GUNBubbleProvider({
  rpcUrl: "http://localhost:8545",
  chain: "localhost",
  gun: gunInstance,
  keypair: userKeypair
});

// Create and use bubble
const bubble = await gunProvider.handleCreateBubble({
  name: "My Secure Bubble",
  isPrivate: true,
  userAddress: userAddress
});

// Upload file - content stored in GUN
await gunProvider.handleFileUpload(
  bubble.id,
  "secret.txt",
  "Secret content",
  userAddress
);
Example: Hybrid Provider

// Initialize Hybrid provider
const hybridProvider = new HybridBubbleProvider({
  rpcUrl: "http://localhost:8545",
  chain: "localhost",
  gun: gunInstance,
  keypair: userKeypair
});

// Create and use bubble
const bubble = await hybridProvider.handleCreateBubble({
  name: "My Hybrid Bubble",
  isPrivate: true,
  userAddress: userAddress
});

// Upload file - content stored in filesystem
await hybridProvider.handleFileUpload(
  bubble.id,
  "large-file.txt",
  "Large content",
  userAddress
);
When to Use Each Provider
Use GUN Provider when: Use Hybrid Provider when:
  • You need full P2P replication
  • Working with small files
  • Building fully decentralized apps
  • Real-time sync is priority
  • Handling large files
  • Need filesystem access
  • Performance is critical
  • Running on server/node environment

📋 Bubble Templates Source

Ready-to-Use Templates

What are Gun-ETH Templates?

Gun-ETH templates provide production-ready implementations for both client and provider setups. These templates include best practices, proper error handling, and common configurations to help you get started quickly with secure and scalable implementations.

Available Templates
  • Client Template: Source
    • Complete configuration management
    • File handling (text, JSON, binary)
    • Comprehensive error handling
    • Secure file storage patterns
  • Provider Template: Source
    • Express server setup
    • Gun node configuration
    • Storage directory management
    • API endpoint implementation
Template Features
  • Environment Configuration: Environment variable support
  • Security Best Practices: Built-in security measures
  • Scalability Patterns: Ready for production loads
  • Documentation: Inline comments and examples
Getting Started
  1. Clone the template repository
  2. Configure environment variables
  3. Customize implementation as needed
  4. Deploy your application

Ready-to-Use Templates


// template-bubble-client.js
// Complete client implementation with:
// - Configuration management
// - File handling (text, JSON, binary)
// - Comprehensive error handling
// - Decrypted file storage

const CONFIG = {
    RPC_URL: process.env.RPC_URL,
    PRIVATE_KEY: process.env.PRIVATE_KEY,
    PROVIDER_URL: "http://localhost:3000/api",
    GUN_PEERS: ['http://localhost:8765/gun'],
    DECRYPTED_FILES_DIR: './decrypted-files'
};

// Initialize client with configuration
const client = await initializeClient();

// Example usage
const bubble = await client.createBubble("Test Bubble");
await client.writeBubble(bubble.id, "test.txt", "content");
const result = await client.readBubble(bubble.id, "test.txt");

// template-bubble-provider.js
// Complete provider implementation with:
// - Express server setup
// - GUN configuration
// - Directory management
// - Error handling
// - Optional external storage integration

const CONFIG = {
    RPC_URL: process.env.RPC_URL,
    PRIVATE_KEY: process.env.PRIVATE_KEY,
    GUN_PEERS: "http://localhost:8765/gun",
    GUN_DIR: "radata",
    BUBBLES_DIR: "bubbles"
};

// Initialize provider with configuration
const app = express();
const gun = Gun(gunOptions);
const provider = new HybridBubbleProvider(CONFIG);

// API endpoints
app.post('/bubble', handleCreateBubble);
app.post('/bubble/:id/write', handleWriteBubble);
app.get('/bubble/:id', handleReadBubble);

Support the Project

Author

Created by scobru

Released by Plancia Foundation

Donations

If you find this project useful, consider supporting its development:

ETH: 0xb542E27732a390f509fD1FF6844a8386fe320f7f

Support the Project

Author

Created by scobru

Released by Plancia Foundation

Donations

If you find this project useful, consider supporting its development:

ETH: 0xb542E27732a390f509fD1FF6844a8386fe320f7f