Skip to content

Commit

Permalink
updated accounts restructure, continuing from mixs changes
Browse files Browse the repository at this point in the history
  • Loading branch information
rh0delta committed Aug 28, 2024
1 parent 9cc1c67 commit 249ca3e
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 231 deletions.
55 changes: 48 additions & 7 deletions src/account/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ import { EntropyAccount } from "./main";
import { ACCOUNTS_CONTENT } from './constants'
import * as config from '../config'
import { cliWrite, endpointOption, passwordOption } from "../common/utils-cli";
import { updateConfig } from "src/common/utils";

export async function entropyAccountCommand (entropy: Entropy, rootCommand: Command) {
const accountCommand = rootCommand.command('account')
.description('Commands to work with accounts on the Entropy Network')

entropyAccountList(entropy, accountCommand)
entropyAccountNew(entropy, accountCommand)
entropyAccountList(accountCommand)
entropyAccountNew(accountCommand)
}

function entropyAccountNew (entropy: Entropy, accountCommand: Command) {
function entropyAccountNew (accountCommand: Command) {
accountCommand.command('create')
.alias('new')
.description('Create a new entropy account from scratch. Output is JSON of form {name, address}')
Expand All @@ -29,15 +30,20 @@ function entropyAccountNew (entropy: Entropy, accountCommand: Command) {
.action(async (name, opts) => {
const { endpoint, path } = opts

const service = new EntropyAccount(entropy, endpoint)
const service = new EntropyAccount({ endpoint })
const newAccount = await service.create({
name,
path
})

const storedConfig = await config.get()
const { accounts } = storedConfig
accounts.push(newAccount)
// WIP - sort out the updateConfig stuff
await service.updateConfig(storedConfig, newAccount)
await updateConfig(storedConfig, {
accounts,
selectedAccount: newAccount.address
})

cliWrite({
name: newAccount.name,
Expand All @@ -48,17 +54,52 @@ function entropyAccountNew (entropy: Entropy, accountCommand: Command) {

}

function entropyAccountList (entropy: Entropy, accountCommand: Command) {
function entropyAccountList (accountCommand: Command) {
accountCommand.command('list')
.alias('ls')
.description('List all accounts. Output is JSON of form [{ name, address, verifyingKeys }]')
.addOption(endpointOption())
.action(async (options) => {
// TODO: test if it's an encrypted account, if no password provided, throw because later on there's no protection from a prompt coming up
const storedConfig = await config.get()
const service = new EntropyAccount(entropy, options.endpoint)
const service = new EntropyAccount({ endpoint: options.endpoint })
const accounts = service.list(storedConfig.accounts)
cliWrite(accounts)
process.exit(0)
})
}

/* register */
// program.command('register')
// .description('Register an entropy account with a program')
// .argument('address', 'Address of existing entropy account')
// .addOption(passwordOption())
// .addOption(endpointOption())
// .addOption(
// new Option(
// '-pointer, --pointer',
// 'Program pointer of program to be used for registering'
// )
// )
// .addOption(
// new Option(
// '-data, --program-data',
// 'Path to file containing program data in JSON format'
// )
// )
// .action(async (address, opts) => {
// const storedConfig = await config.get()
// const { accounts } = storedConfig
// const accountsCommand = new EntropyAccount(entropy, opts.endpoint)
// writeOut('Attempting to register account with addtess: ' + address)
// const accountToRegister = getSelectedAccount(accounts, address)
// if (!accountToRegister) {
// throw new Error('AccountError: Unable to register non-existent account')
// }
// const updatedAccount = await accountsCommand.registerAccount(accountToRegister)
// const arrIdx = accounts.indexOf(accountToRegister)
// accounts.splice(arrIdx, 1, updatedAccount)
// await updateConfig(storedConfig, { accounts, selectedAccount: updatedAccount.address })
// writeOut("Your address" + updatedAccount.address + "has been successfully registered.")
// process.exit(0)
// })
79 changes: 57 additions & 22 deletions src/account/interaction.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,73 @@
import inquirer from "inquirer";
import Entropy from "@entropyxyz/sdk";

import { getSelectedAccount, print } from "../common/utils"
import { EntropyAccountConfig, EntropyConfig } from "../config/types";
import { EntropyAccount } from './main'
import { print } from "src/common/utils"
import * as config from '../config'

import {
manageAccountsQuestions,
newAccountQuestions,
registerAccount,
selectAccountQuestions
} from "./utils";
import Entropy from "@entropyxyz/sdk";
import { EntropyConfig } from "src/config/types";
} from "./utils"


export async function entropyManageAccounts (entropy: Entropy, endpoint: string, storedConfig: EntropyConfig) {
const AccountService = new EntropyAccount(entropy, endpoint)
export async function entropyManageAccounts (endpoint: string, storedConfig: EntropyConfig) {
const AccountService = new EntropyAccount({ endpoint })
const { accounts } = storedConfig
const { interactionChoice } = await inquirer.prompt(manageAccountsQuestions)
switch (interactionChoice) {
case 'create-import': {
let { seed, name, path, importKey } = await inquirer.prompt(newAccountQuestions)
if (importKey && seed.includes('#debug')) {
// isDebugMode = true
seed = seed.split('#debug')[0]
}
const newAccount = await AccountService.create({ seed, name, path })
case 'create-import': {
const answers = await inquirer.prompt(newAccountQuestions)
const { name, path, importKey } = answers
let { seed } = answers
if (importKey && seed.includes('#debug')) {
// isDebugMode = true
seed = seed.split('#debug')[0]
}
case 'list-account': {

const newAccount = await AccountService.create({ seed, name, path })
accounts.push(newAccount)
return {
accounts,
selectedAccount: newAccount.address
}
case 'select-account': {

}
case 'select-account': {
const { selectedAccount } = await inquirer.prompt(selectAccountQuestions(accounts))

print('Current selected account is ' + selectedAccount)
return {
accounts: storedConfig.accounts,
selectedAccount: selectedAccount.address
}
case 'exit': {
}
case 'list-account': {
const list = this.list(accounts)
list?.forEach((account: EntropyAccountConfig)=> print(account))
return
}
case 'exit': {
return 'exit'
}
default:
throw new Error('AccountsError: Unknown interaction action')
}
}

}
export async function entropyRegister (entropy: Entropy, endpoint: string, storedConfig: EntropyConfig): Promise<Partial<EntropyConfig>> {
const AccountService = new EntropyAccount({ entropy, endpoint })

const { accounts, selectedAccount } = storedConfig
const currentAccount = getSelectedAccount(accounts, selectedAccount)
if (!currentAccount) {
print("No account selected to register")
return;
}
return { accounts: responses.accounts ? responses.accounts : storedConfig.accounts, selectedAccount: responses.selectedAccount || storedConfig.selectedAccount }
print("Attempting to register the address:", currentAccount.address)
const updatedAccount = await AccountService.registerAccount(currentAccount)
const arrIdx = accounts.indexOf(currentAccount)
accounts.splice(arrIdx, 1, updatedAccount)
print("Your address", updatedAccount.address, "has been successfully registered.")

return { accounts, selectedAccount }
}
162 changes: 55 additions & 107 deletions src/account/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@ import Keyring from '@entropyxyz/sdk/keys'
import { randomAsHex } from '@polkadot/util-crypto'

import { EntropyBase } from "../common/entropy-base";
import { print, updateConfig } from "../common/utils";
import { EntropyAccountConfig, EntropyConfig } from "../config/types";
import { EntropyAccountConfig } from "../config/types";

import { FLOW_CONTEXT } from "./constants";
import { AccountCreateParams, AccountListResults } from "./types";
import { AccountCreateParams, AccountRegisterParams } from "./types";
import { print } from "src/common/utils";
import { formatAccountsList } from "./utils";

export class EntropyAccount extends EntropyBase {
// NOTE: this class is different - it doesn't need an entropy instance
constructor (entropy: Entropy | null, endpoint: string) {
super(entropy, endpoint, FLOW_CONTEXT)
// Entropy does not need to be required, as only register needs it
// Idea: We could use entropy as an argument for the register method,
// the base class has been updated to optionally require entropy in the
// constructor.
constructor ({ entropy, endpoint }: { entropy?: Entropy, endpoint: string }) {
super({ entropy, endpoint, flowContext: FLOW_CONTEXT })
}

async create ({ seed = randomAsHex(32), name, path }: AccountCreateParams): Promise<EntropyAccountConfig> {
Expand Down Expand Up @@ -44,106 +49,49 @@ export class EntropyAccount extends EntropyBase {
return formatAccountsList(accountsArray)
}

// WIP: Extract all these things into => interaction.ts

// public async newAccount (params?: AccountCreateParams): Promise<EntropyAccountConfig> {
// let { seed, name, path } = params
// let importKey: boolean

// if (!seed && !name && !path) {
// }

// if (importKey && seed.includes('#debug')) {
// seed = seed.split('#debug')[0]
// }

// }

// public async updateConfig (storedConfig: EntropyConfig, newAccount: EntropyAccountConfig): Promise<any> {
// const { accounts } = storedConfig
// accounts.push(newAccount)
//
// return updateConfig(storedConfig, { accounts, selectedAccount: newAccount.address })
// }

// public async selectAccount (accounts: EntropyAccountConfig[]) {
// const answers = await inquirer.prompt(selectAccountQuestions(accounts))
//
// return { selectedAccount: answers.selectedAccount.address }
// }

// public async getUserInput (): Promise<AccountCreateParams> {
// const answers = await inquirer.prompt(newAccountQuestions)
// const { secret, name, path, importKey } = answers
// let seed: string
//
// // never create debug keys only ever import them
// if (importKey && secret.includes('#debug')) {
// // isDebugMode = true
// seed = secret.split('#debug')[0]
// } else {
// seed = importKey ? secret : randomAsHex(32)
// }
//
// return { seed, name, path }
// }

// public async registerAccount (account: EntropyAccountConfig): Promise<EntropyAccountConfig> {
// this.logger.debug(
// 'about to register selectedAccount.address' +
// account.address + 'keyring:' +
// // @ts-expect-error Type export of ChildKey still not available from SDK
// this.entropy.keyring.getLazyLoadAccountProxy('registration').pair.address,
// 'REGISTER'
// )

// try {
// const verifyingKey = await registerAccount(this.entropy)
//
// account?.data?.registration?.verifyingKeys?.push(verifyingKey)
// return account
// } catch (error) {
// this.logger.error('There was a problem registering', error)
// throw error
// }
// }

// public async runInteraction (config): Promise<any> {
// const { accounts } = config
// const { interactionChoice } = await inquirer.prompt(manageAccountsQuestions)
//
// switch (interactionChoice) {
// case 'create-account': {
// const createAccountParams = await this.getUserInput()
// const newAccount = await this.newAccount(createAccountParams)
// print('New Account:')
// print({ name: newAccount.name, address: newAccount.address })
// accounts.push(newAccount)
// return { accounts, selectedAccount: newAccount.address }
// }
// case 'select-account': {
// const response = await this.selectAccount(config.accounts)
// print('Current selected account is ' + response.selectedAccount)
// return response
// }
// case 'list-account': {
// const list = this.list(accounts)
// list?.forEach(account => print(account))
// return
// }
// case 'exit': {
// return 'exit'
// }
// default:
// throw new Error('AccountsError: Unknown interaction action')
// }
// }
}
private async register (params?: AccountRegisterParams): Promise<string> {
const { programModAddress, programData } = params
let verifyingKey: string
try {
const registerParams = programModAddress && programData ? { programDeployer: programModAddress, programData } : undefined

verifyingKey = await this.entropy.register(registerParams)
return verifyingKey
} catch (error) {
if (!verifyingKey) {
try {
const tx = this.entropy.substrate.tx.registry.pruneRegistration()
await tx.signAndSend(this.entropy.keyring.accounts.registration.pair, ({ status }) => {
if (status.isFinalized) {
print('Successfully pruned registration');
}
})
} catch (error) {
console.error('Unable to prune registration due to:', error.message);
throw error
}
}
throw error
}
}

function formatAccountsList (accounts: EntropyAccountConfig[]): AccountListResults[] {
return accounts.map((account: EntropyAccountConfig) => ({
name: account.name,
address: account.address,
verifyingKeys: account?.data?.admin?.verifyingKeys
}))
async registerAccount (account: EntropyAccountConfig, registerParams?: AccountRegisterParams): Promise<EntropyAccountConfig> {
this.logger.debug(
'about to register selectedAccount.address' +
account.address + 'keyring:' +
// @ts-expect-error Type export of ChildKey still not available from SDK
this.entropy.keyring.getLazyLoadAccountProxy('registration').pair.address,
'REGISTER'
)
// Register params to be defined from user input (arguments/options or inquirer prompts)
try {
const verifyingKey = await this.register(registerParams)

account?.data?.registration?.verifyingKeys?.push(verifyingKey)
return account
} catch (error) {
this.logger.error('There was a problem registering', error)
throw error
}
}
}
2 changes: 1 addition & 1 deletion src/account/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface AccountCreateParams {
name: string
seed: string
seed?: string
path?: string
}

Expand Down
Loading

0 comments on commit 249ca3e

Please sign in to comment.