Skip to content

Commit

Permalink
Merge branch 'naynay/file-restructure' into naynay/faucet-restructure
Browse files Browse the repository at this point in the history
  • Loading branch information
rh0delta committed Sep 24, 2024
2 parents 3a9fb9a + 34e4c69 commit 0693af4
Show file tree
Hide file tree
Showing 28 changed files with 398 additions and 290 deletions.
4 changes: 2 additions & 2 deletions src/account/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { EntropyAccount } from "./main";
import { selectAndPersistNewAccount } from "./utils";
import { ACCOUNTS_CONTENT } from './constants'
import * as config from '../config'
import { cliWrite, currentAccountAddressOption, endpointOption, loadEntropy, passwordOption } from "../common/utils-cli";
import { cliWrite, accountOption, endpointOption, loadEntropy, passwordOption } from "../common/utils-cli";
import { findAccountByAddressOrName } from "src/common/utils";

export function entropyAccountCommand () {
Expand Down Expand Up @@ -87,7 +87,7 @@ function entropyAccountRegister () {
.description('Register an entropy account with a program')
.addOption(passwordOption())
.addOption(endpointOption())
.addOption(currentAccountAddressOption())
.addOption(accountOption())
// Removing these options for now until we update the design to accept program configs
// .addOption(
// new Option(
Expand Down
4 changes: 2 additions & 2 deletions src/account/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const FLOW_CONTEXT = 'ENTROPY_ACCOUNTS'
export const FLOW_CONTEXT = 'ENTROPY_ACCOUNT'

export const ACCOUNTS_CONTENT = {
seed: {
Expand Down Expand Up @@ -33,4 +33,4 @@ export const ACCOUNTS_CONTENT = {
{ name: 'Exit to Main Menu', value: 'exit' }
]
}
}
}
12 changes: 6 additions & 6 deletions src/account/interaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ import { EntropyConfig } from "../config/types";
import * as config from "../config";

import {
manageAccountsQuestions,
newAccountQuestions,
selectAccountQuestions
accountManageQuestions,
accountNewQuestions,
accountSelectQuestions
} from "./utils"

/*
* @returns partialConfigUpdate | "exit" | undefined
*/
export async function entropyAccount (endpoint: string, storedConfig: EntropyConfig) {
const { accounts } = storedConfig
const { interactionChoice } = await inquirer.prompt(manageAccountsQuestions)
const { interactionChoice } = await inquirer.prompt(accountManageQuestions)

switch (interactionChoice) {

case 'create-import': {
const answers = await inquirer.prompt(newAccountQuestions)
const answers = await inquirer.prompt(accountNewQuestions)
const { name, path, importKey } = answers
let { seed } = answers
if (importKey && seed.includes('#debug')) {
Expand All @@ -44,7 +44,7 @@ export async function entropyAccount (endpoint: string, storedConfig: EntropyCon
console.error('There are currently no accounts available, please create or import a new account using the Manage Accounts feature')
return
}
const { selectedAccount } = await inquirer.prompt(selectAccountQuestions(accounts))
const { selectedAccount } = await inquirer.prompt(accountSelectQuestions(accounts))
await config.set({
...storedConfig,
selectedAccount: selectedAccount.address
Expand Down
10 changes: 5 additions & 5 deletions src/account/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function validateSeedInput (seed) {
return ACCOUNTS_CONTENT.seed.invalidSeed
}

export const importQuestions = [
export const accountImportQuestions = [
{
type: 'input',
name: ACCOUNTS_CONTENT.seed.name,
Expand All @@ -48,29 +48,29 @@ export const importQuestions = [
},
]

export const newAccountQuestions = [
export const accountNewQuestions = [
{
type: 'confirm',
name: ACCOUNTS_CONTENT.importKey.name,
message: ACCOUNTS_CONTENT.importKey.message,
default: ACCOUNTS_CONTENT.importKey.default,
},
...importQuestions,
...accountImportQuestions,
{
type: 'input',
name: ACCOUNTS_CONTENT.name.name,
default: ACCOUNTS_CONTENT.name.default,
},
]

export const selectAccountQuestions = (accounts: EntropyAccountConfig[]) => [{
export const accountSelectQuestions = (accounts: EntropyAccountConfig[]) => [{
type: 'list',
name: ACCOUNTS_CONTENT.selectAccount.name,
message: ACCOUNTS_CONTENT.selectAccount.message,
choices: generateAccountChoices(accounts)
}]

export const manageAccountsQuestions = [
export const accountManageQuestions = [
{
type: 'list',
name: ACCOUNTS_CONTENT.interactionChoice.name,
Expand Down
2 changes: 1 addition & 1 deletion src/balance/command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Entropy from "@entropyxyz/sdk";
import { Command } from "commander";
import Entropy from "@entropyxyz/sdk";
import { cliWrite, endpointOption, loadEntropy, passwordOption } from "src/common/utils-cli";
import { EntropyBalance } from "./main";

Expand Down
25 changes: 17 additions & 8 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,24 @@
import { Command, Option } from 'commander'

import { EntropyTuiOptions } from './types'
import { currentAccountAddressOption, endpointOption, loadEntropy } from './common/utils-cli'
import { accountOption, endpointOption, loadEntropy } from './common/utils-cli'
import * as config from './config'

import launchTui from './tui'
import { entropyAccountCommand } from './account/command'
import { entropyTransferCommand } from './transfer/command'
import { entropySignCommand } from './sign/command'
import { entropyBalanceCommand } from './balance/command'
import { entropyProgramCommand } from './program/command'

const program = new Command()

/* no command */
program
.name('entropy')
.description('CLI interface for interacting with entropy.xyz. Running this binary without any commands or arguments starts a text-based interface.')
.addOption(currentAccountAddressOption())
.addOption(accountOption())
.addOption(endpointOption())
// NOTE: I think this is currently unused
.addOption(
new Option(
'-d, --dev',
Expand All @@ -33,10 +34,18 @@ program
.addCommand(entropyAccountCommand())
.addCommand(entropyTransferCommand())
.addCommand(entropySignCommand())
.action(async (options: EntropyTuiOptions) => {
const { account, endpoint } = options
const entropy = await loadEntropy(account, endpoint)
launchTui(entropy, options)
.addCommand(entropyProgramCommand())
.action(async (opts: EntropyTuiOptions) => {
const { account, endpoint } = opts
const entropy = account
? await loadEntropy(account, endpoint)
: undefined
// NOTE: on initial startup you have no account
launchTui(entropy, opts)
})
.hook('preAction', async () => {
// set up config file, run migrations
return config.init()
})

program.parseAsync().then(() => {})
program.parseAsync()
49 changes: 32 additions & 17 deletions src/common/utils-cli.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import Entropy from '@entropyxyz/sdk'
import { Option } from 'commander'
import { findAccountByAddressOrName, stringify } from './utils'
import * as config from '../config'
import Entropy from '@entropyxyz/sdk'
import { initializeEntropy } from './initializeEntropy'

export function cliWrite (result) {
const prettyResult = stringify(result, 0)
process.stdout.write(prettyResult)
}

function getConfigOrNull () {
try {
return config.getSync()
} catch (err) {
if (config.isDangerousReadError(err)) throw err
return null
}
}

export function endpointOption () {
return new Option(
'-e, --endpoint <endpoint>',
Expand All @@ -17,14 +26,14 @@ export function endpointOption () {
'Can also be given a stored endpoint name from config eg: `entropy --endpoint test-net`.'
].join(' ')
)
.env('ENDPOINT')
.env('ENTROPY_ENDPOINT')
.argParser(aliasOrEndpoint => {
/* see if it's a raw endpoint */
if (aliasOrEndpoint.match(/^wss?:\/\//)) return aliasOrEndpoint

/* look up endpoint-alias */
const storedConfig = config.getSync()
const endpoint = storedConfig.endpoints[aliasOrEndpoint]
const storedConfig = getConfigOrNull()
const endpoint = storedConfig?.endpoints?.[aliasOrEndpoint]
if (!endpoint) throw Error('unknown endpoint alias: ' + aliasOrEndpoint)

return endpoint
Expand All @@ -40,31 +49,37 @@ export function passwordOption (description?: string) {
)
}

export function currentAccountAddressOption () {
const storedConfig = config.getSync()
export function accountOption () {
const storedConfig = getConfigOrNull()

return new Option(
'-a, --account <address>',
'Sets the current account for the session or defaults to the account stored in the config'
'-a, --account <accountAddressOrName>',
[
'Sets the account for the session.',
'Defaults to the last set account (or the first account if one has not been set before).'
].join(' ')
)
.env('ACCOUNT_ADDRESS')
.env('ENTROPY_ACCOUNT')
.argParser(async (account) => {
if (account === storedConfig.selectedAccount) return account
// Updated selected account in config with new address from this option
const newConfigUpdates = { selectedAccount: account }
await config.set({ ...storedConfig, ...newConfigUpdates })
if (storedConfig && storedConfig.selectedAccount !== account) {
// Updated selected account in config with new address from this option
await config.set({
...storedConfig,
selectedAccount: account
})
}

return account
})
.default(storedConfig.selectedAccount)
.default(storedConfig?.selectedAccount)
// TODO: display the *name* not address
// TODO: standardise whether selectedAccount is name or address.
}

export async function loadEntropy (addressOrName: string, endpoint: string, password?: string): Promise<Entropy> {
const storedConfig = config.getSync()
const selectedAccount = findAccountByAddressOrName(storedConfig.accounts, addressOrName)
if (!selectedAccount) throw new Error(`AddressError: No account with name or address "${addressOrName}"`)
const accounts = getConfigOrNull()?.accounts || []
const selectedAccount = findAccountByAddressOrName(accounts, addressOrName)
if (!selectedAccount) throw new Error(`No account with name or address: "${addressOrName}"`)

// check if data is encrypted + we have a password
if (typeof selectedAccount.data === 'string' && !password) {
Expand Down
2 changes: 1 addition & 1 deletion src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export function accountChoicesWithOther (accounts: EntropyAccountConfig[]) {
}

export function findAccountByAddressOrName (accounts: EntropyAccountConfig[], aliasOrAddress: string) {
if (!aliasOrAddress || !aliasOrAddress.length) throw Error('aliasOrAddress required')
if (!aliasOrAddress || !aliasOrAddress.length) throw Error('account name or address required')

return (
accounts.find(account => account.address === aliasOrAddress) ||
Expand Down
38 changes: 18 additions & 20 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { readFile, writeFile, rm } from 'node:fs/promises'
import { readFileSync, writeFileSync } from 'node:fs'
import { readFileSync } from 'node:fs'
import { mkdirp } from 'mkdirp'
import { join, dirname } from 'path'
import envPaths from 'env-paths'
Expand Down Expand Up @@ -35,9 +35,10 @@ function hasRunMigration (config: any, version: number) {

export async function init (configPath = CONFIG_PATH, oldConfigPath = OLD_CONFIG_PATH) {
const currentConfig = await get(configPath)
.catch(async (err) => {
if (err.code !== 'ENOENT') throw err
.catch(async (err ) => {
if (isDangerousReadError(err)) throw err

// If there is no current config, try loading the old one
const oldConfig = await get(oldConfigPath).catch(noop) // drop errors
if (oldConfig) {
// move the config
Expand All @@ -58,33 +59,30 @@ export async function init (configPath = CONFIG_PATH, oldConfigPath = OLD_CONFIG
export async function get (configPath = CONFIG_PATH) {
return readFile(configPath, 'utf-8')
.then(deserialize)
.catch(makeGetErrorHandler(configPath))
}

export function getSync (configPath = CONFIG_PATH): EntropyConfig {
try {
const configBuffer = readFileSync(configPath, 'utf8')
return deserialize(configBuffer)
} catch (err) {
return makeGetErrorHandler(configPath)(err)
}
export function getSync (configPath = CONFIG_PATH) {
const configStr = readFileSync(configPath, 'utf8')
return deserialize(configStr)
}

export async function set (config: EntropyConfig, configPath = CONFIG_PATH) {
assertConfigPath(configPath)

await mkdirp(dirname(configPath))
await writeFile(configPath, serialize(config))
}

/* util */
function noop () {}

function makeGetErrorHandler (configPath) {
return function getErrorHandler (err) {
if (err.code !== 'ENOENT') throw err

const newConfig = migrateData(allMigrations, {})
mkdirp.sync(dirname(configPath))
writeFileSync(configPath, serialize(newConfig))
return newConfig
function assertConfigPath (configPath) {
if (!configPath.endsWith('.json')) {
throw Error(`configPath must be of form *.json, got ${configPath}`)
}
}
export function isDangerousReadError (err) {
// file not found:
if (err.code === 'ENOENT') return false

return true
}
5 changes: 3 additions & 2 deletions src/faucet/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { EntropyBase } from "../common/entropy-base";
import { blake2AsHex, encodeAddress } from "@polkadot/util-crypto";
import { FAUCET_PROGRAM_MOD_KEY, TESTNET_PROGRAM_HASH } from "./utils";
import { EntropyBalance } from "src/balance/main";
import { viewPrograms } from "src/flows/programs/view";
import { EntropyProgram } from "src/program/main";
import FaucetSigner from "./helpers/signer";
import { SendMoneyParams } from "./types";

Expand Down Expand Up @@ -76,11 +76,12 @@ export class EntropyFaucet extends EntropyBase {
}: SendMoneyParams
): Promise<any> {
const balanceService = new EntropyBalance(this.entropy, this.endpoint)
const programService = new EntropyProgram(this.entropy, this.endpoint)
// check balance of faucet address
const balance = await balanceService.getBalance(faucetAddress)
if (balance <= 0) throw new Error('FundsError: Faucet Account does not have funds')
// check verifying key for only one program matching the program hash
const programs = await viewPrograms(this.entropy, { verifyingKey: chosenVerifyingKey })
const programs = await programService.list({ verifyingKey: chosenVerifyingKey })
if (programs.length) {
if (programs.length > 1) throw new Error('ProgramsError: Faucet Account has too many programs attached, expected less')
if (programs.length === 1 && programs[0].program_pointer !== faucetProgramPointer) {
Expand Down
1 change: 0 additions & 1 deletion src/flows/index.ts

This file was deleted.

12 changes: 0 additions & 12 deletions src/flows/programs/add.ts

This file was deleted.

Loading

0 comments on commit 0693af4

Please sign in to comment.