getting erc20 addresses optionally after running node

This commit is contained in:
Kumaraguru 2025-01-13 19:20:52 +00:00
parent 5a51c8a3a3
commit 60a9576fbe
No known key found for this signature in database
GPG Key ID: 4E4555A84ECD28F7
3 changed files with 174 additions and 33 deletions

View File

@ -1,6 +1,6 @@
{
"name": "codexstorage",
"version": "1.0.7",
"version": "1.0.8",
"description": "CLI tool for Codex Storage",
"main": "index.js",
"type": "module",

View File

@ -1,7 +1,7 @@
import { createSpinner } from 'nanospinner';
import { runCommand } from '../utils/command.js';
import { showErrorMessage, showInfoMessage, showSuccessMessage } from '../utils/messages.js';
import { isNodeRunning, isCodexInstalled, logToSupabase } from '../services/nodeService.js';
import { isNodeRunning, isCodexInstalled, logToSupabase, startPeriodicLogging, getWalletAddress, setWalletAddress } from '../services/nodeService.js';
import inquirer from 'inquirer';
import boxen from 'boxen';
import chalk from 'chalk';
@ -11,6 +11,22 @@ import axios from 'axios';
const platform = os.platform();
async function promptForWalletAddress() {
const { wallet } = await inquirer.prompt([
{
type: 'input',
name: 'wallet',
message: 'Please enter your ERC20 wallet address (or press enter to skip):',
validate: (input) => {
if (!input) return true; // Allow empty input
if (/^0x[a-fA-F0-9]{40}$/.test(input)) return true;
return 'Please enter a valid ERC20 wallet address (0x followed by 40 hexadecimal characters) or press enter to skip';
}
}
]);
return wallet || null;
}
export async function runCodex(showNavigationMenu) {
const isInstalled = await isCodexInstalled();
if (!isInstalled) {
@ -84,7 +100,28 @@ export async function runCodex(showNavigationMenu) {
try {
const response = await axios.get('http://localhost:8080/api/codex/v1/debug/info');
if (response.status === 200) {
await logToSupabase(response.data);
// Check if wallet exists
try {
const existingWallet = await getWalletAddress();
if (!existingWallet) {
console.log(showInfoMessage('[OPTIONAL] Please provide your ERC20 wallet address.'));
const wallet = await promptForWalletAddress();
if (wallet) {
await setWalletAddress(wallet);
console.log(showSuccessMessage('Wallet address saved successfully!'));
}
}
} catch (error) {
console.log(showErrorMessage('Failed to process wallet address. Continuing without wallet update.'));
}
// Start periodic logging
const stopLogging = await startPeriodicLogging();
nodeProcess.on('exit', () => {
stopLogging();
});
console.log(boxen(
chalk.cyan('We are logging some of your node\'s public data for improving the Codex experience'),
{
@ -131,10 +168,11 @@ async function showNodeDetails(data, showNavigationMenu) {
choices: [
'1. View Connected Peers',
'2. View Node Information',
'3. Back to Main Menu',
'4. Exit'
'3. Update Wallet Address',
'4. Back to Main Menu',
'5. Exit'
],
pageSize: 4,
pageSize: 5,
loop: true
}
]);
@ -183,8 +221,31 @@ async function showNodeDetails(data, showNavigationMenu) {
));
return showNodeDetails(data, showNavigationMenu);
case '3':
return showNavigationMenu();
try {
const existingWallet = await getWalletAddress();
console.log(boxen(
`${chalk.cyan('Current wallet address:')}\n${existingWallet || 'Not set'}`,
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'blue'
}
));
const wallet = await promptForWalletAddress();
if (wallet) {
await setWalletAddress(wallet);
console.log(showSuccessMessage('Wallet address updated successfully!'));
}
} catch (error) {
console.log(showErrorMessage(`Failed to update wallet address: ${error.message}`));
}
return showNodeDetails(data, showNavigationMenu);
case '4':
return showNavigationMenu();
case '5':
process.exit(0);
}
}

View File

@ -5,6 +5,21 @@ import os from 'os';
const platform = os.platform();
// Add a variable to store wallet address in memory
let currentWallet = null;
export async function setWalletAddress(wallet) {
// Basic ERC20 address validation
if (wallet && !/^0x[a-fA-F0-9]{40}$/.test(wallet)) {
throw new Error('Invalid ERC20 wallet address format');
}
currentWallet = wallet;
}
export async function getWalletAddress() {
return currentWallet;
}
export async function isNodeRunning() {
try {
const response = await axios.get('http://localhost:8080/api/codex/v1/debug/info');
@ -23,36 +38,53 @@ export async function isCodexInstalled() {
}
}
export async function logToSupabase(nodeData) {
try {
const peerCount = nodeData.table.nodes ? nodeData.table.nodes.length : "0";
const payload = {
nodeId: nodeData.table.localNode.nodeId,
peerId: nodeData.table.localNode.peerId,
publicIp: nodeData.announceAddresses[0].split('/')[2],
version: nodeData.codex.version,
peerCount: peerCount == 0 ? "0" : peerCount,
port: nodeData.announceAddresses[0].split('/')[4],
listeningAddress: nodeData.table.localNode.address
};
export async function logToSupabase(nodeData, retryCount = 3, retryDelay = 1000) {
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const response = await axios.post('https://vfcnsjxahocmzefhckfz.supabase.co/functions/v1/codexnodes', payload, {
headers: {
'Content-Type': 'application/json'
}
});
return response.status === 200;
} catch (error) {
console.error('Failed to log to Supabase:', error.message);
if (error.response) {
console.error('Error response:', {
status: error.response.status,
data: error.response.data
for (let attempt = 1; attempt <= retryCount; attempt++) {
try {
const peerCount = nodeData.table.nodes ? nodeData.table.nodes.length : "0";
const payload = {
nodeId: nodeData.table.localNode.nodeId,
peerId: nodeData.table.localNode.peerId,
publicIp: nodeData.announceAddresses[0].split('/')[2],
version: nodeData.codex.version,
peerCount: peerCount == 0 ? "0" : peerCount,
port: nodeData.announceAddresses[0].split('/')[4],
listeningAddress: nodeData.table.localNode.address,
timestamp: new Date().toISOString(),
wallet: currentWallet // Include wallet address in payload
};
const response = await axios.post('https://vfcnsjxahocmzefhckfz.supabase.co/functions/v1/codexnodes', payload, {
headers: {
'Content-Type': 'application/json'
},
timeout: 5000 // 5 second timeout
});
return response.status === 200;
} catch (error) {
const isLastAttempt = attempt === retryCount;
const isNetworkError = error.code === 'ENOTFOUND' || error.code === 'ETIMEDOUT' || error.code === 'ECONNREFUSED';
if (isLastAttempt || !isNetworkError) {
console.error(`Failed to log to Supabase (attempt ${attempt}/${retryCount}):`, error.message);
if (error.response) {
console.error('Error response:', {
status: error.response.status,
data: error.response.data
});
}
if (isLastAttempt) return false;
} else {
// Only log retry attempts for network errors
console.log(`Retrying Supabase log (attempt ${attempt}/${retryCount}) after ${retryDelay}ms...`);
await delay(retryDelay);
}
}
return false;
}
return false;
}
export async function checkDependencies() {
@ -70,4 +102,52 @@ export async function checkDependencies() {
}
}
return true;
}
export async function startPeriodicLogging() {
const FIFTEEN_MINUTES = 15 * 60 * 1000; // 15 minutes in milliseconds
const logNodeInfo = async () => {
try {
const response = await axios.get('http://localhost:8080/api/codex/v1/debug/info');
if (response.status === 200) {
await logToSupabase(response.data);
}
} catch (error) {
// Silently handle any logging errors to not disrupt the node operation
console.error('Failed to log node info:', error.message);
}
};
// Initial log
await logNodeInfo();
// Set up periodic logging
const intervalId = setInterval(logNodeInfo, FIFTEEN_MINUTES);
// Return cleanup function
return () => clearInterval(intervalId);
}
export async function updateWalletAddress(nodeId, wallet) {
// Basic ERC20 address validation
if (!/^0x[a-fA-F0-9]{40}$/.test(wallet)) {
throw new Error('Invalid ERC20 wallet address format');
}
try {
const response = await axios.post('https://vfcnsjxahocmzefhckfz.supabase.co/functions/v1/wallet', {
nodeId,
wallet
}, {
headers: {
'Content-Type': 'application/json'
},
timeout: 5000
});
return response.status === 200;
} catch (error) {
console.error('Failed to update wallet address:', error.message);
throw error;
}
}