// json-precompile-mainnet.js
const { ethers } = require('ethers');
const { JSON_PRECOMPILE_ABI, JSON_PRECOMPILE_ADDRESS } = require('@sei-js/precompiles');
require('dotenv').config();
// Safe extraction utilities
async function safeExtractBytes(jsonPrecompile, data, key, defaultValue = '') {
try {
const inputData = ethers.toUtf8Bytes(JSON.stringify(data));
const result = await jsonPrecompile.extractAsBytes(inputData, key);
return ethers.toUtf8String(result);
} catch (error) {
console.log(` ⚠️ Key "${key}" not found, using default: "${defaultValue}"`);
return defaultValue;
}
}
async function safeExtractUint256(jsonPrecompile, data, key, defaultValue = 0n) {
try {
const inputData = ethers.toUtf8Bytes(JSON.stringify(data));
const result = await jsonPrecompile.extractAsUint256(inputData, key);
return result;
} catch (error) {
console.log(` ⚠️ Key "${key}" not found or invalid integer, using default: ${defaultValue}`);
return defaultValue;
}
}
async function safeExtractBytesList(jsonPrecompile, data, key, defaultValue = []) {
try {
const inputData = ethers.toUtf8Bytes(JSON.stringify(data));
const result = await jsonPrecompile.extractAsBytesList(inputData, key);
return result.map((bytes) => ethers.toUtf8String(bytes));
} catch (error) {
console.log(` ⚠️ Key "${key}" not found or invalid array, using default: [${defaultValue.join(', ')}]`);
return defaultValue;
}
}
async function main() {
try {
// Connect to Sei Mainnet
console.log('🌐 Connecting to Sei Mainnet...');
const provider = new ethers.JsonRpcProvider('https://evm-rpc.sei-apis.com');
// Use private key from environment variables (secure approach)
const privateKey = process.env.PRIVATE_KEY;
if (!privateKey) {
throw new Error('Please set PRIVATE_KEY in .env file');
}
const wallet = new ethers.Wallet(privateKey, provider);
console.log(`👤 Wallet address: ${wallet.address}`);
// Check balance
const balance = await provider.getBalance(wallet.address);
const balanceEther = ethers.formatEther(balance);
console.log(`💰 Wallet balance: ${balanceEther} SEI\n`);
// Initialize JSON precompile contract
const jsonPrecompile = new ethers.Contract(JSON_PRECOMPILE_ADDRESS, JSON_PRECOMPILE_ABI, wallet);
console.log('📄 === Sei Mainnet JSON Precompile Demo ===\n');
// Complex sample data - simulating a real-world oracle response
const oracleData = {
market: {
prices: {
SEI: 275, // 2.75 USD (stored as integer with 2 decimal places)
BTC: 5000000, // 50,000.00 USD
ETH: 300000 // 3,000.00 USD
},
volume: {
daily: 1500000000, // $15M daily volume
weekly: 8500000000 // $85M weekly volume
}
},
metadata: {
timestamp: '2024-12-27T12:00:00Z',
source: 'MainnetPriceOracle',
version: '2.1.0',
isLive: 1 // 1 = true, 0 = false
},
assets: ['SEI', 'BTC', 'ETH', 'USDC'],
validators: {
active: 125,
total: 200
}
};
console.log('📋 Input JSON Data:');
console.log(JSON.stringify(oracleData, null, 2));
console.log();
// 1. Extract string data with error handling
console.log('1️⃣ Extracting String Data...');
// Extract metadata object first, then parse individual fields
const metadataBytes = await jsonPrecompile.extractAsBytes(ethers.toUtf8Bytes(JSON.stringify(oracleData)), 'metadata');
const metadata = JSON.parse(ethers.toUtf8String(metadataBytes));
console.log(` 📊 Source: ${metadata.source}`);
console.log(` 🔢 Version: ${metadata.version}`);
console.log(` ⏰ Timestamp: ${metadata.timestamp}`);
console.log(` 🟢 Is Live: ${metadata.isLive === 1 ? 'Yes' : 'No'}`);
// Test missing key
const missingKey = await safeExtractBytes(jsonPrecompile, oracleData, 'nonexistent', 'N/A');
console.log(` ❓ Missing Key: ${missingKey}`);
// 2. Extract numeric data with proper object parsing
console.log('\n2️⃣ Extracting Numeric Data...');
// Extract market object first
const marketBytes = await jsonPrecompile.extractAsBytes(ethers.toUtf8Bytes(JSON.stringify(oracleData)), 'market');
const market = JSON.parse(ethers.toUtf8String(marketBytes));
// Extract validators object
const validatorsBytes = await jsonPrecompile.extractAsBytes(ethers.toUtf8Bytes(JSON.stringify(oracleData)), 'validators');
const validators = JSON.parse(ethers.toUtf8String(validatorsBytes));
// Convert integers back to decimals
const seiPrice = market.prices.SEI / 100; // 2 decimal places
const btcPrice = market.prices.BTC / 100; // 2 decimal places
const isLive = metadata.isLive === 1; // Convert to boolean
console.log(` 💰 SEI Price: ${seiPrice} (raw: ${market.prices.SEI})`);
console.log(` ₿ BTC Price: ${btcPrice.toLocaleString()} (raw: ${market.prices.BTC})`);
console.log(` 💹 Daily Volume: ${market.volume.daily.toLocaleString()}`);
console.log(` ✅ Active Validators: ${validators.active}`);
console.log(` 🔴 Is Live: ${isLive} (raw: ${metadata.isLive})`);
// 3. Extract array data
console.log('\n3️⃣ Extracting Array Data...');
const assets = await safeExtractBytesList(jsonPrecompile, oracleData, 'assets');
const invalidArray = await safeExtractBytesList(jsonPrecompile, oracleData, 'invalid.array', ['DEFAULT']);
console.log(` 🪙 Assets: [${assets.join(', ')}]`);
console.log(` ❌ Invalid Array: [${invalidArray.join(', ')}]`);
// 4. Extract complex nested objects
console.log('\n4️⃣ Extracting Complex Nested Data...');
console.log(' 📈 Market Data:');
console.log(` Prices: SEI=${market.prices.SEI / 100}, BTC=${market.prices.BTC / 100}, ETH=${market.prices.ETH / 100}`);
console.log(` Volume: Daily=${market.volume.daily.toLocaleString()}, Weekly=${market.volume.weekly.toLocaleString()}`);
console.log(` 👥 Validator Data:`);
console.log(` Active: ${validators.active}, Total: ${validators.total}`);
// 5. Gas optimization demonstration
console.log('\n5️⃣ Gas Usage Analysis...');
const gasEstimates = {
small: 50000, // Simple key extraction
medium: 80000, // Nested object extraction
large: 120000 // Complex array/object processing
};
console.log(' ⛽ Recommended Gas Limits:');
console.log(` Simple extraction: ${gasEstimates.small.toLocaleString()} gas`);
console.log(` Nested extraction: ${gasEstimates.medium.toLocaleString()} gas`);
console.log(` Complex processing: ${gasEstimates.large.toLocaleString()} gas`);
// 6. Performance test with corrected key extraction
console.log('\n6️⃣ Performance & Error Testing...');
const testCases = [
{ key: 'metadata', expected: 'object', description: 'metadata object' },
{ key: 'market', expected: 'object', description: 'market data' },
{ key: 'assets', expected: 'array', description: 'assets array' },
{ key: 'nonexistent', expected: 'error', description: 'missing key' }
];
for (const testCase of testCases) {
try {
const start = Date.now();
const result = await safeExtractBytes(jsonPrecompile, oracleData, testCase.key);
const duration = Date.now() - start;
const preview = result.length > 50 ? result.substring(0, 47) + '...' : result;
console.log(` ✅ ${testCase.description}: "${preview}" (${duration}ms)`);
} catch (error) {
console.log(` ❌ ${testCase.description}: ${error.message}`);
}
}
console.log('\n🎉 === JSON Precompile Demo Completed Successfully! ===');
} catch (error) {
console.error('\n❌ Error:', error.message);
console.log('\n🔧 Troubleshooting tips:');
console.log('1. Ensure PRIVATE_KEY is set in .env file');
console.log('2. Verify sufficient SEI balance for gas fees');
console.log('3. Check network connectivity to Sei mainnet');
console.log('4. Validate JSON structure before processing');
process.exit(1);
}
}
// Run the demo
main().catch(console.error);