Skill: rojasjuniore/virtuals (version 1.0.0)

--- name: virtuals version: 1.0.0 description: "Virtuals Protocol integration for OpenClaw. Create, manage and trade tokenized AI agents on Base." metadata: {"openclaw": {"emoji": "🎭", "homepage": "https://virtuals.io"}} --- # Virtuals Protocol Skill 🎭 Create, manage and trade tokenized AI agents on Virtuals Protocol (Base L2). ## Features - 📊 **List agents** - Browse top AI agents on Virtuals - 💰 **Check prices** - Get agent token prices and market data - 🔍 **Agent details** - View agent info, holders, transactions - 🚀 **Create agent** - Launch your own tokenized AI agent - 💸 **Trade** - Buy/sell agent tokens ## Installation ```bash clawhub install virtuals cd ~/.openclaw/skills/virtuals npm install && npm run build && npm link ``` ## Quick Start ```bash # Check $VIRTUAL price virtuals price # List top agents virtuals agents list # Get agent details virtuals agents info <agent-name> # Check your balance virtuals balance <wallet-address> ``` ## Commands ### Market Data ```bash virtuals price # $VIRTUAL price and market cap virtuals agents list [--top 10] # List top agents by market cap virtuals agents trending # Trending agents (24h volume) ``` ### Agent Info ```bash virtuals agents info <name> # Agent details virtuals agents holders <name> # Top holders virtuals agents trades <name> # Recent trades ``` ### Wallet ```bash virtuals balance <address> # Check $VIRTUAL balance virtuals portfolio <address> # All agent tokens held ``` ### Create Agent (requires funds) ```bash virtuals create --name "MyAgent" --ticker "AGENT" --description "..." ``` ### Trade (requires funds) ```bash virtuals buy <agent> <amount> # Buy agent tokens virtuals sell <agent> <amount> # Sell agent tokens ``` ## Configuration Set your wallet for trading: ```bash virtuals config --wallet <address> --private-key <key> ``` **⚠️ TESTNET ONLY for now** - Don't use mainnet funds. ## Architecture ``` ┌─────────────────────────────────────┐ │ virtuals CLI │ ├─────────────────────────────────────┤ │ @virtuals-protocol/game SDK │ │ + ethers.js (Base L2) │ ├─────────────────────────────────────┤ │ Virtuals Protocol Contracts │ │ • VIRTUAL Token │ │ • Agent Factory │ │ • Bonding Curves │ │ • Uniswap V2 Pools │ └─────────────────────────────────────┘ ``` ## Contract Addresses (Base) | Contract | Address | |----------|---------| | $VIRTUAL | [REDACTED_SECRET] | ## Resources - Virtuals App: https://app.virtuals.io - Fun (create agents): https://fun.virtuals.io - Whitepaper: https://whitepaper.virtuals.io - GAME SDK: https://github.com/game-by-virtuals/game-node ## License MIT --- **Built for OpenClaw by IntechChain 🦞**

path: dist/cli.d.ts
content: #!/usr/bin/env node
/**
 * Virtuals Protocol CLI for OpenClaw
 * Create, manage and trade tokenized AI agents
 */
export {};


path: dist/cli.js
content: #!/usr/bin/env node
"use strict";
/**
 * Virtuals Protocol CLI for OpenClaw
 * Create, manage and trade tokenized AI agents
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const ethers_1 = require("ethers");
const axios_1 = __importDefault(require("axios"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const CONFIG_DIR = path.join(process.env.HOME || '', '.openclaw', 'virtuals');
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
// Contract addresses (Base Mainnet)
const CONTRACTS = {
    VIRTUAL_TOKEN: [REDACTED_SECRET],
    // Add more as we discover them
};
// Base RPC
const BASE_RPC = 'https://mainnet.base.org';
// ERC20 ABI (minimal)
const ERC20_ABI = [
    'function balanceOf(address) view returns (uint256)',
    'function decimals() view returns (uint8)',
    'function symbol() view returns (string)',
    'function name() view returns (string)',
    'function totalSupply() view returns (uint256)',
];
// Helpers
function ensureDir() {
    if (!fs.existsSync(CONFIG_DIR)) {
        fs.mkdirSync(CONFIG_DIR, { recursive: true });
    }
}
function loadConfig() {
    try {
        if (fs.existsSync(CONFIG_FILE)) {
            return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
        }
    }
    catch (e) { }
    return {};
}
function saveConfig(config) {
    ensureDir();
    fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
    fs.chmodSync(CONFIG_FILE, 0o600);
}
function getProvider() {
    return new ethers_1.ethers.JsonRpcProvider(BASE_RPC);
}
async function getVirtualPrice() {
    try {
        const response = await axios_1.default.get('https://api.coingecko.com/api/v3/simple/price?ids=virtual-protocol&vs_currencies=usd&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true');
        const data = response.data['virtual-protocol'];
        return {
            price: data.usd,
            marketCap: data.usd_market_cap,
            change24h: data.usd_24h_change,
            volume24h: data.usd_24h_vol,
        };
    }
    catch (e) {
        throw new Error('Failed to fetch price data');
    }
}
async function getTopAgents() {
    // Note: Virtuals doesn't have a public API for this
    // We'll need to scrape or use their internal API
    // For now, return placeholder
    try {
        // Try to get from their API if it exists
        const response = await axios_1.default.get('https://api.virtuals.io/agents?limit=10', {
            timeout: 5000,
        }).catch(() => null);
        if (response?.data) {
            return response.data;
        }
        // Fallback: Return well-known agents
        return [
            { name: 'aixbt', ticker: 'AIXBT', description: 'AI Trading Analysis Agent' },
            { name: 'Luna', ticker: 'LUNA', description: 'Virtual K-Pop Idol' },
            { name: 'Butler', ticker: 'BUTLER', description: 'Virtuals Protocol Interface Agent' },
        ];
    }
    catch (e) {
        return [];
    }
}
// CLI
const program = new commander_1.Command();
program
    .name('virtuals')
    .description('Virtuals Protocol - Tokenized AI Agents on Base')
    .version('1.0.0');
// Price command
program
    .command('price')
    .description('Get $VIRTUAL token price and market data')
    .action(async () => {
    console.log('💰 Fetching $VIRTUAL price...\n');
    try {
        const data = await getVirtualPrice();
        console.log('═══════════════════════════════════════');
        console.log('         $VIRTUAL Token');
        console.log('═══════════════════════════════════════');
        console.log(`  Price:      $${data.price.toFixed(4)}`);
        console.log(`  Market Cap: $${(data.marketCap / 1e6).toFixed(2)}M`);
        console.log(`  24h Change: ${data.change24h >= 0 ? '+' : ''}${data.change24h.toFixed(2)}%`);
        console.log(`  24h Volume: $${(data.volume24h / 1e6).toFixed(2)}M`);
        console.log('═══════════════════════════════════════');
        console.log(`\n  Contract: ${CONTRACTS.VIRTUAL_TOKEN}`);
        console.log('  Chain: Base (L2)');
    }
    catch (e) {
        console.error('❌ Error:', e.message);
    }
});
// Agents commands
const agents = program.command('agents').description('AI Agent operations');
agents
    .command('list')
    .description('List top AI agents')
    .option('--top <n>', 'Number of agents to show', '10')
    .action(async (options) => {
    console.log('🤖 Top AI Agents on Virtuals\n');
    try {
        const agentList = await getTopAgents();
        console.log('═══════════════════════════════════════════════════');
        console.log('  #  | Agent          | Ticker    | Description');
        console.log('═══════════════════════════════════════════════════');
        agentList.slice(0, parseInt(options.top)).forEach((agent, i) => {
            const name = (agent.name || 'Unknown').padEnd(14);
            const ticker = ('$' + (agent.ticker || '???')).padEnd(10);
            const desc = (agent.description || '').slice(0, 30);
            console.log(`  ${(i + 1).toString().padStart(2)} | ${name} | ${ticker} | ${desc}`);
        });
        console.log('═══════════════════════════════════════════════════');
        console.log('\n  📍 View all: https://app.virtuals.io');
    }
    catch (e) {
        console.error('❌ Error:', e.message);
    }
});
agents
    .command('info <name>')
    .description('Get agent details')
    .action(async (name) => {
    console.log(`🔍 Looking up agent: ${name}\n`);
    // For now, show placeholder info
    console.log('═══════════════════════════════════════');
    console.log(`  Agent: ${name}`);
    console.log('═══════════════════════════════════════');
    console.log('  ℹ️  Full agent info requires Virtuals API access');
    console.log(`  📍 View on app: https://app.virtuals.io/agents/${name}`);
    console.log('');
});
// Balance command
program
    .command('balance <address>')
    .description('Check $VIRTUAL balance')
    .action(async (address) => {
    console.log(`💳 Checking balance for ${address.slice(0, 10)}...`);
    try {
        const provider = getProvider();
        const token = new ethers_1.ethers.Contract(CONTRACTS.VIRTUAL_TOKEN, ERC20_ABI, provider);
        const balance = await token.balanceOf(address);
        const decimals = await token.decimals();
        const formatted = ethers_1.ethers.formatUnits(balance, decimals);
        const priceData = await getVirtualPrice();
        const usdValue = parseFloat(formatted) * priceData.price;
        console.log('\n═══════════════════════════════════════');
        console.log('         $VIRTUAL Balance');
        console.log('═══════════════════════════════════════');
        console.log(`  Balance: ${parseFloat(formatted).toFixed(2)} VIRTUAL`);
        console.log(`  Value:   $${usdValue.toFixed(2)} USD`);
        console.log('═══════════════════════════════════════');
    }
    catch (e) {
        console.error('❌ Error:', e.message);
    }
});
// Create agent command
program
    .command('create')
    .description('Create a new AI agent (requires funds)')
    .requiredOption('--name <name>', 'Agent name')
    .requiredOption('--ticker <ticker>', 'Token ticker (max 6 chars)')
    .requiredOption('--description <desc>', 'Agent description')
    .option('--image <url>', 'Profile image URL')
    .action(async (options) => {
    console.log('🚀 Creating Agent on Virtuals\n');
    const config = loadConfig();
    if (!config.privateKey) {
        console.log('❌ No wallet configured. Run:');
        console.log('   virtuals config --wallet <address> --private-key <key>');
        return;
    }
    console.log('Agent Details:');
    console.log(`  Name: ${options.name}`);
    console.log(`  Ticker: $${options.ticker}`);
    console.log(`  Description: ${options.description}`);
    console.log('');
    console.log('⚠️  Creating agents requires:');
    console.log('   • 1,000 $VIRTUAL (~$590)');
    console.log('   • ETH for gas on Base');
    console.log('');
    console.log('📍 For now, create agents at: https://fun.virtuals.io');
    console.log('   (Smart contract integration coming soon)');
});
// Config command
program
    .command('config')
    .description('Configure wallet for trading')
    .option('--wallet <address>', 'Wallet address')
    .option('--private-key <key>', 'Private key (stored securely)')
    .option('--show', 'Show current config')
    .action(async (options) => {
    if (options.show) {
        const config = loadConfig();
        console.log('\n⚙️  Virtuals Configuration');
        console.log('═══════════════════════════════════════');
        console.log(`  Wallet: ${config.wallet || 'Not set'}`);
        console.log(`  Key:    ${config.privateKey ? '••••••••' : 'Not set'}`);
        console.log('═══════════════════════════════════════');
        return;
    }
    const config = loadConfig();
    if (options.wallet) {
        config.wallet = options.wallet;
    }
    if (options.privateKey) {
        config.privateKey = options.privateKey;
    }
    saveConfig(config);
    console.log('✅ Configuration saved');
});
// Info command
program
    .command('info')
    .description('Show Virtuals Protocol info')
    .action(() => {
    console.log(`
╔═══════════════════════════════════════════════════════════╗
║              VIRTUALS PROTOCOL                            ║
║           Society of AI Agents                            ║
╠═══════════════════════════════════════════════════════════╣
║                                                           ║
║  Virtuals Protocol enables tokenized AI agents that       ║
║  can coordinate, transact, and generate value onchain.    ║
║                                                           ║
║  Key Features:                                            ║
║  • Tokenized AI Agents (each with own token)              ║
║  • Agent Commerce Protocol (agent-to-agent payments)      ║
║  • GAME Framework (agent development)                     ║
║  • Revenue sharing with token holders                     ║
║                                                           ║
║  Costs:                                                   ║
║  • Create Agent: ~1,000 VIRTUAL (~$590)                   ║
║  • Graduation: 42,000 VIRTUAL accumulated                 ║
║  • LP locked for 10 years                                 ║
║                                                           ║
║  Links:                                                   ║
║  • App: https://app.virtuals.io                           ║
║  • Create: https://fun.virtuals.io                        ║
║  • Docs: https://whitepaper.virtuals.io                   ║
║                                                           ║
╚═══════════════════════════════════════════════════════════╝
`);
});
program.parse();
//# sourceMappingURL=cli.js.map

path: package-lock.json
content: {
  "name": "virtuals",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "virtuals",
      "version": "1.0.0",
      "license": "MIT",
      "dependencies": {
        "axios": "^1.6.0",
        "commander": "^12.1.0",
        "ethers": "^6.9.0"
      },
      "bin": {
        "virtuals": "dist/cli.js"
      },
      "devDependencies": {
        "@types/node": "^20.0.0",
        "typescript": "^5.0.0"
      }
    },
    "node_modules/@adraffy/ens-normalize": {
      "version": "1.10.1",
      "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/@noble/curves": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@noble/hashes": "1.3.2"
      },
      "funding": {
        "url": "https://paulmillr.com/funding/"
      }
    },
    "node_modules/@noble/hashes": {
      "version": "1.3.2",
      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 16"
      },
      "funding": {
        "url": "https://paulmillr.com/funding/"
      }
    },
    "node_modules/@types/node": {
      "version": "20.19.33",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz",
      "integrity": [REDACTED_SECRET],
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "undici-types": "~6.21.0"
      }
    },
    "node_modules/aes-js": {
      "version": "4.0.0-beta.5",
      "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/asynckit": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/axios": {
      "version": "1.13.5",
      "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "follow-redirects": "^1.15.11",
        "form-data": "^4.0.5",
        "proxy-from-env": "^1.1.0"
      }
    },
    "node_modules/call-bind-apply-helpers": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "function-bind": "^1.1.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/combined-stream": {
      "version": "1.0.8",
      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "delayed-stream": "~1.0.0"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/commander": {
      "version": "12.1.0",
      "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/delayed-stream": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=0.4.0"
      }
    },
    "node_modules/dunder-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.1",
        "es-errors": "^1.3.0",
        "gopd": "^1.2.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-define-property": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-errors": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-object-atoms": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-set-tostringtag": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.6",
        "has-tostringtag": "^1.0.2",
        "hasown": "^2.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/ethers": {
      "version": "6.16.0",
      "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "individual",
          "url": "https://github.com/sponsors/ethers-io/"
        },
        {
          "type": "individual",
          "url": "https://www.buymeacoffee.com/ricmoo"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "@adraffy/ens-normalize": "1.10.1",
        "@noble/curves": "1.2.0",
        "@noble/hashes": "1.3.2",
        "@types/node": "22.7.5",
        "aes-js": "4.0.0-beta.5",
        "tslib": "2.7.0",
        "ws": "8.17.1"
      },
      "engines": {
        "node": ">=14.0.0"
      }
    },
    "node_modules/ethers/node_modules/@types/node": {
      "version": "22.7.5",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "undici-types": "~6.19.2"
      }
    },
    "node_modules/ethers/node_modules/undici-types": {
      "version": "6.19.8",
      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/follow-redirects": {
      "version": "1.15.11",
      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "individual",
          "url": "https://github.com/sponsors/RubenVerborgh"
        }
      ],
      "license": "MIT",
      "engines": {
        "node": ">=4.0"
      },
      "peerDependenciesMeta": {
        "debug": {
          "optional": true
        }
      }
    },
    "node_modules/form-data": {
      "version": "4.0.5",
      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "asynckit": "^0.4.0",
        "combined-stream": "^1.0.8",
        "es-set-tostringtag": "^2.1.0",
        "hasown": "^2.0.2",
        "mime-types": "^2.1.12"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/function-bind": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-intrinsic": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.2",
        "es-define-property": "^1.0.1",
        "es-errors": "^1.3.0",
        "es-object-atoms": "^1.1.1",
        "function-bind": "^1.1.2",
        "get-proto": "^1.0.1",
        "gopd": "^1.2.0",
        "has-symbols": "^1.1.0",
        "hasown": "^2.0.2",
        "math-intrinsics": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "dunder-proto": "^1.0.1",
        "es-object-atoms": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/gopd": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-symbols": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-tostringtag": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "has-symbols": "^1.0.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/hasown": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "function-bind": "^1.1.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/math-intrinsics": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/mime-db": {
      "version": "1.52.0",
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/mime-types": {
      "version": "2.1.35",
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "mime-db": "1.52.0"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/proxy-from-env": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/tslib": {
      "version": "2.7.0",
      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "0BSD"
    },
    "node_modules/typescript": {
      "version": "5.9.3",
      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
      "integrity": [REDACTED_SECRET],
      "dev": true,
      "license": "Apache-2.0",
      "bin": {
        "tsc": "bin/tsc",
        "tsserver": "bin/tsserver"
      },
      "engines": {
        "node": ">=14.17"
      }
    },
    "node_modules/undici-types": {
      "version": "6.21.0",
      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
      "integrity": [REDACTED_SECRET],
      "dev": true,
      "license": "MIT"
    },
    "node_modules/ws": {
      "version": "8.17.1",
      "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=10.0.0"
      },
      "peerDependencies": {
        "bufferutil": "^4.0.1",
        "utf-8-validate": ">=5.0.2"
      },
      "peerDependenciesMeta": {
        "bufferutil": {
          "optional": true
        },
        "utf-8-validate": {
          "optional": true
        }
      }
    }
  }
}


path: package.json
content: {
  "name": "virtuals",
  "version": "1.0.0",
  "description": "Virtuals Protocol integration for OpenClaw - Create, manage and trade AI agent tokens",
  "main": "dist/cli.js",
  "bin": {
    "virtuals": "./dist/cli.js"
  },
  "scripts": {
    "build": "tsc",
    "start": "node dist/cli.js"
  },
  "keywords": ["openclaw", "virtuals", "ai-agents", "base", "tokens"],
  "author": "IntechChain",
  "license": "MIT",
  "dependencies": {
    "commander": "^12.1.0",
    "ethers": "^6.9.0",
    "axios": "^1.6.0"
  },
  "devDependencies": {
    "@types/node": "^20.0.0",
    "typescript": "^5.0.0"
  }
}


path: src/cli.ts
content: #!/usr/bin/env node
/**
 * Virtuals Protocol CLI for OpenClaw
 * Create, manage and trade tokenized AI agents
 */

import { Command } from 'commander';
import { ethers } from 'ethers';
import axios from 'axios';
import * as fs from 'fs';
import * as path from 'path';

const CONFIG_DIR = path.join(process.env.HOME || '', '.openclaw', 'virtuals');
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');

// Contract addresses (Base Mainnet)
const CONTRACTS = {
  VIRTUAL_TOKEN: [REDACTED_SECRET],
  // Add more as we discover them
};

// Base RPC
const BASE_RPC = 'https://mainnet.base.org';

// ERC20 ABI (minimal)
const ERC20_ABI = [
  'function balanceOf(address) view returns (uint256)',
  'function decimals() view returns (uint8)',
  'function symbol() view returns (string)',
  'function name() view returns (string)',
  'function totalSupply() view returns (uint256)',
];

interface Config {
  wallet?: string;
  privateKey?: string;
}

// Helpers
function ensureDir(): void {
  if (!fs.existsSync(CONFIG_DIR)) {
    fs.mkdirSync(CONFIG_DIR, { recursive: true });
  }
}

function loadConfig(): Config {
  try {
    if (fs.existsSync(CONFIG_FILE)) {
      return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
    }
  } catch (e) {}
  return {};
}

function saveConfig(config: Config): void {
  ensureDir();
  fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
  fs.chmodSync(CONFIG_FILE, 0o600);
}

function getProvider(): ethers.JsonRpcProvider {
  return new ethers.JsonRpcProvider(BASE_RPC);
}

async function getVirtualPrice(): Promise<{ price: number; marketCap: number; change24h: number; volume24h: number }> {
  try {
    const response = await axios.get(
      'https://api.coingecko.com/api/v3/simple/price?ids=virtual-protocol&vs_currencies=usd&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true'
    );
    const data = response.data['virtual-protocol'];
    return {
      price: data.usd,
      marketCap: data.usd_market_cap,
      change24h: data.usd_24h_change,
      volume24h: data.usd_24h_vol,
    };
  } catch (e) {
    throw new Error('Failed to fetch price data');
  }
}

async function getTopAgents(): Promise<any[]> {
  // Note: Virtuals doesn't have a public API for this
  // We'll need to scrape or use their internal API
  // For now, return placeholder
  try {
    // Try to get from their API if it exists
    const response = await axios.get('https://api.virtuals.io/agents?limit=10', {
      timeout: 5000,
    }).catch(() => null);
    
    if (response?.data) {
      return response.data;
    }
    
    // Fallback: Return well-known agents
    return [
      { name: 'aixbt', ticker: 'AIXBT', description: 'AI Trading Analysis Agent' },
      { name: 'Luna', ticker: 'LUNA', description: 'Virtual K-Pop Idol' },
      { name: 'Butler', ticker: 'BUTLER', description: 'Virtuals Protocol Interface Agent' },
    ];
  } catch (e) {
    return [];
  }
}

// CLI
const program = new Command();

program
  .name('virtuals')
  .description('Virtuals Protocol - Tokenized AI Agents on Base')
  .version('1.0.0');

// Price command
program
  .command('price')
  .description('Get $VIRTUAL token price and market data')
  .action(async () => {
    console.log('💰 Fetching $VIRTUAL price...\n');
    
    try {
      const data = await getVirtualPrice();
      
      console.log('═══════════════════════════════════════');
      console.log('         $VIRTUAL Token');
      console.log('═══════════════════════════════════════');
      console.log(`  Price:      $${data.price.toFixed(4)}`);
      console.log(`  Market Cap: $${(data.marketCap / 1e6).toFixed(2)}M`);
      console.log(`  24h Change: ${data.change24h >= 0 ? '+' : ''}${data.change24h.toFixed(2)}%`);
      console.log(`  24h Volume: $${(data.volume24h / 1e6).toFixed(2)}M`);
      console.log('═══════════════════════════════════════');
      console.log(`\n  Contract: ${CONTRACTS.VIRTUAL_TOKEN}`);
      console.log('  Chain: Base (L2)');
    } catch (e: any) {
      console.error('❌ Error:', e.message);
    }
  });

// Agents commands
const agents = program.command('agents').description('AI Agent operations');

agents
  .command('list')
  .description('List top AI agents')
  .option('--top <n>', 'Number of agents to show', '10')
  .action(async (options) => {
    console.log('🤖 Top AI Agents on Virtuals\n');
    
    try {
      const agentList = await getTopAgents();
      
      console.log('═══════════════════════════════════════════════════');
      console.log('  #  | Agent          | Ticker    | Description');
      console.log('═══════════════════════════════════════════════════');
      
      agentList.slice(0, parseInt(options.top)).forEach((agent, i) => {
        const name = (agent.name || 'Unknown').padEnd(14);
        const ticker = ('$' + (agent.ticker || '???')).padEnd(10);
        const desc = (agent.description || '').slice(0, 30);
        console.log(`  ${(i + 1).toString().padStart(2)} | ${name} | ${ticker} | ${desc}`);
      });
      
      console.log('═══════════════════════════════════════════════════');
      console.log('\n  📍 View all: https://app.virtuals.io');
    } catch (e: any) {
      console.error('❌ Error:', e.message);
    }
  });

agents
  .command('info <name>')
  .description('Get agent details')
  .action(async (name) => {
    console.log(`🔍 Looking up agent: ${name}\n`);
    
    // For now, show placeholder info
    console.log('═══════════════════════════════════════');
    console.log(`  Agent: ${name}`);
    console.log('═══════════════════════════════════════');
    console.log('  ℹ️  Full agent info requires Virtuals API access');
    console.log(`  📍 View on app: https://app.virtuals.io/agents/${name}`);
    console.log('');
  });

// Balance command
program
  .command('balance <address>')
  .description('Check $VIRTUAL balance')
  .action(async (address) => {
    console.log(`💳 Checking balance for ${address.slice(0, 10)}...`);
    
    try {
      const provider = getProvider();
      const token = new ethers.Contract(CONTRACTS.VIRTUAL_TOKEN, ERC20_ABI, provider);
      
      const balance = await token.balanceOf(address);
      const decimals = await token.decimals();
      const formatted = ethers.formatUnits(balance, decimals);
      
      const priceData = await getVirtualPrice();
      const usdValue = parseFloat(formatted) * priceData.price;
      
      console.log('\n═══════════════════════════════════════');
      console.log('         $VIRTUAL Balance');
      console.log('═══════════════════════════════════════');
      console.log(`  Balance: ${parseFloat(formatted).toFixed(2)} VIRTUAL`);
      console.log(`  Value:   $${usdValue.toFixed(2)} USD`);
      console.log('═══════════════════════════════════════');
    } catch (e: any) {
      console.error('❌ Error:', e.message);
    }
  });

// Create agent command
program
  .command('create')
  .description('Create a new AI agent (requires funds)')
  .requiredOption('--name <name>', 'Agent name')
  .requiredOption('--ticker <ticker>', 'Token ticker (max 6 chars)')
  .requiredOption('--description <desc>', 'Agent description')
  .option('--image <url>', 'Profile image URL')
  .action(async (options) => {
    console.log('🚀 Creating Agent on Virtuals\n');
    
    const config = loadConfig();
    if (!config.privateKey) {
      console.log('❌ No wallet configured. Run:');
      console.log('   virtuals config --wallet <address> --private-key <key>');
      return;
    }
    
    console.log('Agent Details:');
    console.log(`  Name: ${options.name}`);
    console.log(`  Ticker: $${options.ticker}`);
    console.log(`  Description: ${options.description}`);
    console.log('');
    
    console.log('⚠️  Creating agents requires:');
    console.log('   • 1,000 $VIRTUAL (~$590)');
    console.log('   • ETH for gas on Base');
    console.log('');
    console.log('📍 For now, create agents at: https://fun.virtuals.io');
    console.log('   (Smart contract integration coming soon)');
  });

// Config command
program
  .command('config')
  .description('Configure wallet for trading')
  .option('--wallet <address>', 'Wallet address')
  .option('--private-key <key>', 'Private key (stored securely)')
  .option('--show', 'Show current config')
  .action(async (options) => {
    if (options.show) {
      const config = loadConfig();
      console.log('\n⚙️  Virtuals Configuration');
      console.log('═══════════════════════════════════════');
      console.log(`  Wallet: ${config.wallet || 'Not set'}`);
      console.log(`  Key:    ${config.privateKey ? '••••••••' : 'Not set'}`);
      console.log('═══════════════════════════════════════');
      return;
    }
    
    const config = loadConfig();
    
    if (options.wallet) {
      config.wallet = options.wallet;
    }
    if (options.privateKey) {
      config.privateKey = options.privateKey;
    }
    
    saveConfig(config);
    console.log('✅ Configuration saved');
  });

// Info command
program
  .command('info')
  .description('Show Virtuals Protocol info')
  .action(() => {
    console.log(`
╔═══════════════════════════════════════════════════════════╗
║              VIRTUALS PROTOCOL                            ║
║           Society of AI Agents                            ║
╠═══════════════════════════════════════════════════════════╣
║                                                           ║
║  Virtuals Protocol enables tokenized AI agents that       ║
║  can coordinate, transact, and generate value onchain.    ║
║                                                           ║
║  Key Features:                                            ║
║  • Tokenized AI Agents (each with own token)              ║
║  • Agent Commerce Protocol (agent-to-agent payments)      ║
║  • GAME Framework (agent development)                     ║
║  • Revenue sharing with token holders                     ║
║                                                           ║
║  Costs:                                                   ║
║  • Create Agent: ~1,000 VIRTUAL (~$590)                   ║
║  • Graduation: 42,000 VIRTUAL accumulated                 ║
║  • LP locked for 10 years                                 ║
║                                                           ║
║  Links:                                                   ║
║  • App: https://app.virtuals.io                           ║
║  • Create: https://fun.virtuals.io                        ║
║  • Docs: https://whitepaper.virtuals.io                   ║
║                                                           ║
╚═══════════════════════════════════════════════════════════╝
`);
  });

program.parse();


path: tsconfig.json
content: {
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)