diff --git a/package.json b/package.json index 98cefa5..7dd4644 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "alchemy-sdk": "^3.1.2", "ansi-colors": "^4.1.3", "cli-progress": "^3.12.0", + "debug": "^4.3.4", "dotenv": "^16.4.1", "ethers": "^5.7.2", "inquirer": "8.0.0", diff --git a/src/common/initializeEntropy.ts b/src/common/initializeEntropy.ts index 5b6ec75..674fe0a 100644 --- a/src/common/initializeEntropy.ts +++ b/src/common/initializeEntropy.ts @@ -2,17 +2,20 @@ import Entropy, { wasmGlobalsReady } from "@entropyxyz/sdk" // TODO: fix importing of types from @entropy/sdk/keys // @ts-ignore import Keyring from "@entropyxyz/sdk/keys" -import { decrypt } from "../flows/password" import inquirer from "inquirer" -// have a main account to use -let defaultAccount +import { decrypt } from "../flows/password" +import { debug } from "../common/utils" + +// TODO: unused +// let defaultAccount // have a main account to use +// let entropys + // have a main keyring const keyrings = { default: undefined } -let entropys -export function getKeyring(address) { +export function getKeyring (address) { if (!address && keyrings.default) return keyrings.default if (address && keyrings[address]) return keyrings[address] if (address && !keyrings[address]) throw new Error('No keyring for this account') @@ -21,13 +24,13 @@ export function getKeyring(address) { } -export function setupKeyrings (config) { - const { accounts } = config; - -} +// export function setupKeyrings (config) { +// const { accounts } = config; +// +// } export const initializeEntropy = async (keyMaterial, endpoint: string): Promise => { - console.log('KEY MATERIAL', keyMaterial); + debug('key material', keyMaterial); // if (defaultAccount && defaultAccount.seed === keyMaterial.seed) return entropys[defaultAccount.registering.address] await wasmGlobalsReady() @@ -76,29 +79,25 @@ export const initializeEntropy = async (keyMaterial, endpoint: string): Promise< throw new Error("Data format is not recognized as either encrypted or unencrypted") } - console.log('account keyMaterial', accountData); - let selectedAccount; + debug('account keyMaterial', accountData); + let selectedAccount if(!keyrings.default) { const keyring = new Keyring({ ...accountData, debug: true }) keyrings.default = keyring selectedAccount = keyring } else { const keyring = new Keyring({ ...accountData, debug: true }) - keyrings[keyring.registration.address] = keyring + keyrings[keyring.accounts.masterAccountView.registration.address] = keyring selectedAccount = keyring } - const entropy = new Entropy({ keyring: selectedAccount, endpoint}) - + const entropy = new Entropy({ keyring: selectedAccount, endpoint }) await entropy.ready - console.log('data sent', accountData); - - console.log('storage', keyrings); - - console.log('selected', selectedAccount); - - console.log('keyring', entropy.keyring); - + + debug('data sent', accountData); + debug('storage', keyrings); + debug('selected', selectedAccount); + debug('keyring', entropy.keyring); if (!entropy?.keyring?.accounts?.registration?.seed) { throw new Error("Keys are undefined") diff --git a/src/common/utils.ts b/src/common/utils.ts index 529f252..bdefb2c 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -2,6 +2,12 @@ import { decodeAddress, encodeAddress } from "@polkadot/keyring" import { hexToU8a, isHex } from "@polkadot/util" import { keccak256 } from "ethereum-cryptography/keccak" import { Buffer } from 'buffer' +import Debug from 'debug' + +const _debug = Debug('@entropyxyz/cli') +export function debug (...args) { + _debug(...args.map(arg => JSON.stringify(arg, null, 2))) +} // hardcoding for now instead of querying chain const DECIMALS = 10 @@ -16,7 +22,7 @@ export function pubToAddress (publicKey: string): string { const publicKeyBuffer = Buffer.from(publicKey, 'hex') const hash = keccak256(publicKeyBuffer) const address = `0x${Buffer.from(hash.subarray(hash.length - 20)).toString('hex')}` - console.log({address}) + debug('address:', address) return address } @@ -60,6 +66,6 @@ export function accountChoices (accounts) { } export function accountChoicesWithOther (accounts) { - return accountChoices(accounts) - .concat([{ name: "Other", value: null }]) + return accountChoices(accounts) + .concat([{ name: "Other", value: null }]) } diff --git a/src/config/migrations/00.ts b/src/config/migrations/00.ts index 323cfb8..6aadd39 100644 --- a/src/config/migrations/00.ts +++ b/src/config/migrations/00.ts @@ -1,5 +1,3 @@ -import { selectAccount } from "../../flows/manage-accounts/select-account" - export const version = '0' export function migrate (data= {}) { diff --git a/src/flows/DeployPrograms/index.ts b/src/flows/DeployPrograms/index.ts index a4ed027..2c84650 100644 --- a/src/flows/DeployPrograms/index.ts +++ b/src/flows/DeployPrograms/index.ts @@ -1,8 +1,9 @@ +import Entropy from "@entropyxyz/sdk" +import * as util from "@polkadot/util" import inquirer from "inquirer" import { initializeEntropy } from "../../common/initializeEntropy" -import { accountChoices } from "../../common/utils" +import { debug, accountChoices } from "../../common/utils" import { readFileSync } from "fs" -import * as util from "@polkadot/util" export async function devPrograms ({ accounts, endpoints }, options) { const endpoint = endpoints[options.ENDPOINT] @@ -15,37 +16,33 @@ export async function devPrograms ({ accounts, endpoints }, options) { const answers = await inquirer.prompt([accountQuestion]) const selectedAccount = answers.selectedAccount - console.log('selectedAccount:', {selectedAccount}) + debug('selectedAccount:', {selectedAccount}) + const choices = { + "Deploy": deployProgram, + "Get Program Pointers": getProgramPointers, + "Exit": () => console.log("Exiting") + } - const actionChoice = await inquirer.prompt ([ + const actionChoice = await inquirer.prompt([ { type: "list", name: "action", message: "Select your action:", - choices: ["Deploy", "Get Program Pointers", "Exit"], + choices: Object.keys(choices) }, ]) const entropy = await initializeEntropy( - { data: selectedAccount.data }, + { keyMaterial: selectedAccount.data }, endpoint ) - switch (actionChoice.action) { - case "Deploy": - await deployProgram(entropy, selectedAccount) - break - case "Get Program Pointers": - await getProgramPointers(entropy, selectedAccount) - break - case "Exit": - console.log("Exiting.") - break - } + const flow = choices[actionChoice.action] + await flow(entropy, selectedAccount) } -async function deployProgram (entropy, account) { +async function deployProgram (entropy: Entropy, account: any) { const deployQuestions = [ { type: "input", @@ -91,12 +88,12 @@ async function deployProgram (entropy, account) { console.error("Deployment failed:", deployError) } - console.log(`Deploying from account: ${account.address}`) + console.log("Deploying from account:", account.address) } -async function getProgramPointers (entropy, account) { +async function getProgramPointers (entropy: Entropy, account: any) { const userAddress = account.address - console.log(userAddress) + debug('Account address:',userAddress) if (!userAddress) return try { @@ -106,12 +103,3 @@ async function getProgramPointers (entropy, account) { console.error("Failed to retrieve program pointers:", error) } } - -// function accountChoices (accounts) { -// return accounts -// .map((account) => ({ -// name: `${account.name} (${account.address})`, -// value: account, -// })) -// .concat([{ name: "Other", value: null }]) -// } diff --git a/src/flows/UserPrograms/index.ts b/src/flows/UserPrograms/index.ts index c878bd6..5b7acef 100644 --- a/src/flows/UserPrograms/index.ts +++ b/src/flows/UserPrograms/index.ts @@ -31,7 +31,7 @@ export async function userPrograms ({ accounts, endpoints }, options) { ]) const entropy = await initializeEntropy( - { data: selectedAccount.data }, + { keyMaterial: selectedAccount.data }, endpoint ) diff --git a/src/flows/entropyFaucet/index.ts b/src/flows/entropyFaucet/index.ts index 155a1f8..e0dd5d0 100644 --- a/src/flows/entropyFaucet/index.ts +++ b/src/flows/entropyFaucet/index.ts @@ -1,5 +1,5 @@ import inquirer from "inquirer" -import { accountChoices } from "../../common/utils" +import { debug, accountChoices } from "../../common/utils" import { initializeEntropy } from "../../common/initializeEntropy" export async function entropyFaucet ({ accounts, endpoints }, options) { @@ -14,7 +14,7 @@ export async function entropyFaucet ({ accounts, endpoints }, options) { const answers = await inquirer.prompt([accountQuestion]) const selectedAccount = answers.selectedAccount - console.log({selectedAccount}) + debug('selectedAccount', selectedAccount) const recipientAddress = selectedAccount.address const aliceData = { @@ -24,7 +24,7 @@ export async function entropyFaucet ({ accounts, endpoints }, options) { }, } - const entropy = await initializeEntropy(aliceData, endpoint) + const entropy = await initializeEntropy({ keyMaterial: aliceData }, endpoint) if (!entropy.registrationManager.signer.pair) { throw new Error("Keys are undefined") diff --git a/src/flows/ethTransaction/index.ts b/src/flows/ethTransaction/index.ts index 70d4185..2ed58ef 100644 --- a/src/flows/ethTransaction/index.ts +++ b/src/flows/ethTransaction/index.ts @@ -4,7 +4,7 @@ import util from 'util' import { ethers } from "ethers" import { http, Hex, createPublicClient } from 'viem' import { sepolia } from 'viem/chains' -import { accountChoices, pubToAddress } from "../../common/utils" +import { accountChoices, debug, pubToAddress } from "../../common/utils" import { initializeEntropy } from "../../common/initializeEntropy" const execAsync = util.promisify(exec) @@ -51,12 +51,11 @@ async function sendCurlCommand (entropySig: string, sepoliaEndpoint: string) { const command = `curl -H "Content-Type: application/json" -d '${JSON.stringify(data)}' '${sepoliaEndpoint}'` const { stdout, stderr } = await execAsync(command) - console.log('CURL Output:', stdout) - if (stderr) { - console.error('CURL Error:', stderr) - } + debug('CURL Output:', stdout) + if (stderr) debug('CURL Error:', stderr) } catch (error) { - console.error('CURL Execution error:', error) + debug('CURL Execution error:', error) + console.error('Error sending transaction') } } @@ -90,9 +89,9 @@ export async function ethTransaction ({ accounts, endpoints }, options): Promise let ethAddress: string try { const verifyingKey = await entropy.getVerifyingKey(address) - console.log({ verifyingKey }) + debug('verifyingKey:', verifyingKey) ethAddress = pubToAddress(verifyingKey) - console.log({ ethAddress }) + debug('ethAddress:', ethAddress) } catch (error) { console.error("Error retrieving verifying key:", error.message) return @@ -119,135 +118,8 @@ export async function ethTransaction ({ accounts, endpoints }, options): Promise const entropySig = await entropy.signWithAdapter({ msg: basicTx, type: 'eth' }) as string const addy = await getSenderAddressFromSignedTx(entropySig) - console.log({ addy }) - - console.log({ entropySig }) + debug('sender address:', addy) + debug('entropy signature:', entropySig) await sendCurlCommand(entropySig, sepoliaEndpoint) } - - -// import inquirer from "inquirer" -// import { exec } from 'child_process' -// import util from 'util' -// import { accountChoices, pubToAddress } from "../../common/utils" -// import { initializeEntropy } from "../../common/initializeEntropy" -// import { ethers } from "ethers" - - -// const execAsync = util.promisify(exec) - -// async function getAccountBalance (address: string, infuraEndpoint: string) { -// const provider = new ethers.providers.JsonRpcProvider(infuraEndpoint) - -// try { -// const balance = await provider.getBalance(address) - -// return balance -// } catch (error) { -// console.error('Failed to get account balance:', error) -// return null -// } -// } - -// async function getSenderAddressFromSignedTx (signedTx: string): Promise { -// try { -// const tx = ethers.utils.parseTransaction(signedTx) -// console.log({tx}) -// return tx.from -// } catch (error) { -// console.error('Error extracting sender address:', error) -// return '' -// } -// } - -// async function sendCurlCommand (entropySig: string, infuraEndpoint: string) { -// const data = { -// id: 1, -// jsonrpc: "2.0", -// method: "eth_sendRawTransaction", -// params: [entropySig], -// } - -// const command = `curl -H "Content-Type: application/json" -d '${JSON.stringify(data)}' '${infuraEndpoint}'` - - -// try { -// const { stdout, stderr } = await execAsync(command) -// console.log('CURL Output:', stdout) -// if (stderr) { -// console.error('CURL Error:', stderr) -// } -// const output = JSON.parse(stdout) -// return output.result -// } catch (error) { -// console.error('CURL Execution error:', error) -// throw error -// } -// } - - -// export async function ethTransaction ({ accounts, endpoints }, options) { -// const endpoint = endpoints[options.ENDPOINT] - -// const accountQuestion = { -// type: "list", -// name: "selectedAccount", -// message: "Choose account:", -// choices: accountChoices(accounts), -// } - -// const answers = await inquirer.prompt([accountQuestion]) -// const selectedAccount = answers.selectedAccount - -// const entropy = await initializeEntropy( -// { data: selectedAccount.data }, -// endpoint -// ) - -// await entropy.ready - -// const address = entropy.account?.sigRequestKey?.wallet.address -// if (address == undefined) { -// throw new Error("address issue") -// } - -// const infuraEndpoint = "https://goerli.infura.io/v3/66a5ebbced6a4fdb8a54d121d054b49c" - -// let ethAddress -// try { -// const verifyingKey = await entropy.getVerifyingKey(address) -// console.log({verifyingKey}) -// ethAddress = pubToAddress(verifyingKey) -// console.log({ethAddress}) -// } catch (error) { -// console.error("Error retrieving verifying key:", error.message) -// return -// } -// const balanceWei = await getAccountBalance(ethAddress, infuraEndpoint) -// if (balanceWei) { -// const balanceEther = ethers.utils.formatEther(balanceWei) -// console.log(`Balance: ${balanceEther} ETH`) -// } else { -// console.log('Could not retrieve account balance.') -// } -// const basicTx = { -// to: '0x772b9a9e8aa1c9db861c6611a82d251db4fac990', -// value: .00001, -// chainId: 5, -// gasLimit: '0x' + Number(21288n).toString(16), -// nonce: 1, -// data: '0x43726561746564204f6e20456e74726f7079' -// } - - - -// const entropySig = await entropy.signTransaction({ txParams: basicTx, type: 'eth' }) as string -// const addy = await getSenderAddressFromSignedTx(entropySig) -// console.log({ addy }) - -// console.log({ entropySig }) - -// await sendCurlCommand(entropySig, infuraEndpoint) - -// } diff --git a/src/flows/manage-accounts/import-key.ts b/src/flows/manage-accounts/import-key.ts index 516f44c..75963df 100644 --- a/src/flows/manage-accounts/import-key.ts +++ b/src/flows/manage-accounts/import-key.ts @@ -1,4 +1,4 @@ -import { mnemonicValidate, mnemonicToMiniSecret } from '@polkadot/util-crypto' +// import { mnemonicValidate, mnemonicToMiniSecret } from '@polkadot/util-crypto' export const importQuestions = [ { @@ -12,14 +12,16 @@ export const importQuestions = [ type: 'input', name: 'secret', message: ({ secretType }) => `${secretType}:`, - validate: (secret, {secretType}) => { + validate: (secret) => { + // validate: (secret, { secretType }) => { console.log('\nsecret:', secret, typeof secret) // if (secretType === 'mnemonic') return mnemonicValidate(secret) ? true : 'not a valid mnemonic' if (secret.length === 66 && secret.startsWith('0x')) return true if (secret.length === 64) return true return 'not a valid seed' }, - filter: (secret, { secretType }) => { + filter: (secret) => { + // filter: (secret, { secretType }) => { // if (secretType === 'mnemonic') { // return mnemonicToMiniSecret(secret) // } diff --git a/src/flows/manage-accounts/index.ts b/src/flows/manage-accounts/index.ts index a8c7599..1945e08 100644 --- a/src/flows/manage-accounts/index.ts +++ b/src/flows/manage-accounts/index.ts @@ -23,5 +23,5 @@ const questions = [{ export async function manageAccounts (config) { const { choice } = await inquirer.prompt(questions) const { accounts, selectedAccount } = await actions[choice](config) - return { accounts: !!accounts ? accounts : config.accounts, selectedAccount } + return { accounts: accounts ? accounts : config.accounts, selectedAccount } } diff --git a/src/flows/register/index.ts b/src/flows/register/index.ts index 3150e1b..a89469e 100644 --- a/src/flows/register/index.ts +++ b/src/flows/register/index.ts @@ -1,5 +1,5 @@ import inquirer from "inquirer" -import { accountChoices } from "../../common/utils" +import { debug, accountChoices } from "../../common/utils" import { initializeEntropy } from "../../common/initializeEntropy" export async function register ({ accounts, endpoints, selectedAccount: selectedFromConfig }, options) { @@ -7,15 +7,13 @@ export async function register ({ accounts, endpoints, selectedAccount: selected if (!selectedFromConfig) return const selectedAccount = accounts.find(obj => obj.address === selectedFromConfig) - console.log('selectedAccount', selectedAccount); + debug('selectedAccount', selectedAccount); const entropy = await initializeEntropy(selectedAccount.data, endpoint) const filteredAccountChoices = accountChoices(accounts).filter(choice => choice.name !== "Other") - - console.log(filteredAccountChoices); - + debug('filteredAccountChoices', filteredAccountChoices); const programModKeyAccountQuestion = { type: "list", @@ -44,8 +42,7 @@ export async function register ({ accounts, endpoints, selectedAccount: selected } else { programModAccount = programModAccountAnswer.programModAccount.address } - console.log('programModAccount', programModAccountAnswer, programModAccount); - + debug('programModAccount', programModAccountAnswer, programModAccount); console.log("Attempting to register the address:", selectedAccount.address) await entropy.register() diff --git a/src/flows/sign/index.ts b/src/flows/sign/index.ts index cec31c0..3892968 100644 --- a/src/flows/sign/index.ts +++ b/src/flows/sign/index.ts @@ -1,9 +1,9 @@ import inquirer from "inquirer" import { ethers } from "ethers" import { initializeEntropy } from "../../common/initializeEntropy" -import { accountChoices, isEmpty } from "../../common/utils" +import { accountChoices, debug, isEmpty } from "../../common/utils" -// TODO revisit this file, rename as signEthTransaction? +// TODO: revisit this file, rename as signEthTransaction? export async function sign ({ accounts, endpoints }, options) { const endpoint = endpoints[options.ENDPOINT] @@ -23,6 +23,7 @@ export async function sign ({ accounts, endpoints }, options) { const answers = await inquirer.prompt([accountQuestion, otherQuestion]) const selectedAccount = answers.selectedAccount + debug("selectedAccount:", selectedAccount) const accountSeedOrPrivateKey = answers.accountSeedOrPrivateKey let keyMaterial = selectedAccount?.data; if (!keyMaterial || isEmpty(keyMaterial)) { @@ -34,7 +35,7 @@ export async function sign ({ accounts, endpoints }, options) { const entropy = await initializeEntropy({ keyMaterial }, endpoint) const { address } = entropy.keyring.accounts.registration - console.log({ address }) + debug("address:", address) if (address == undefined) { throw new Error("address issue") } @@ -86,5 +87,5 @@ export async function sign ({ accounts, endpoints }, options) { type: "eth", })) as string - console.log({ signature }) + console.log('signature:', signature) } diff --git a/src/index.ts b/src/index.ts index 2446dc9..af827bb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import inquirer from 'inquirer' import * as config from './config' import * as flows from './flows' import { ascii } from './common/ascii' -import { getActiveOptions } from './common/utils' +import { debug, getActiveOptions } from './common/utils' config.init() @@ -48,7 +48,6 @@ if (setOptions.DEV_MODE) Object.assign(choices, devChoices) // assign exit so its last Object.assign(choices, { 'Exit': async () => {} }) - const intro = { type: 'list', name: 'choice', @@ -66,13 +65,10 @@ const returnToMainMenu = { main() export async function main () { - let noAccounts: boolean = true const storedConfig = await config.get() + debug('stored config', storedConfig) const { selectedAccount } = storedConfig - - // console.log('stored config', storedConfig); - const answers = await inquirer.prompt([intro]) if (answers.choice === 'Exit') { @@ -91,5 +87,6 @@ export async function main () { const { returnToMain } = await inquirer.prompt([returnToMainMenu]) if (returnToMain) main() + console.log('Have a nice day') }