Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NayNay] File Restructure: Accounts Restructure #215

Merged
merged 33 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4e0532a
[NayNay] File Restructure: Accounts Restructure
rh0delta Aug 5, 2024
af58213
Merge branch 'naynay/file-restructure' into naynay/accounts-restructure
rh0delta Aug 5, 2024
e9411ce
updated new account, list account and selected account with new file …
rh0delta Aug 6, 2024
6d46831
finished updated manage accoutns stuff, updated tests too
rh0delta Aug 6, 2024
8063677
updated register flow and moved methods to accounts namespace
rh0delta Aug 6, 2024
118c5a7
updated register tests
rh0delta Aug 6, 2024
6dfd8b2
cleanup from smoke test
rh0delta Aug 6, 2024
9d22f6a
updated changelog
rh0delta Aug 7, 2024
b59a656
Merge branch 'naynay/file-restructure' into naynay/accounts-restructure
rh0delta Aug 19, 2024
1b7aa6f
start refactor
mixmix Aug 27, 2024
ec0609f
WIP: part way refactored account stuff
mixmix Aug 28, 2024
3aa419b
cleaning up the cleanup for accounts restructure;
rh0delta Aug 28, 2024
9cc1c67
forgot something
rh0delta Aug 28, 2024
249ca3e
updated accounts restructure, continuing from mixs changes
rh0delta Aug 28, 2024
6cd2e9f
Update main.ts
rh0delta Aug 28, 2024
b5af231
Update manage-accounts.test.ts
rh0delta Aug 28, 2024
036936b
Merge branch 'naynay/file-restructure' of github.com:entropyxyz/cli i…
mixmix Aug 29, 2024
9cb1b81
fixups
mixmix Aug 29, 2024
dbbb777
WIP
mixmix Aug 29, 2024
378fffa
fixups
mixmix Aug 29, 2024
d971d4d
compleeeete
mixmix Aug 29, 2024
50ab1e1
get working for fresh install. see WIP
mixmix Aug 29, 2024
b013ce3
fixed fresh install and using tui, might have fixed cli not sure
rh0delta Aug 29, 2024
2272689
updated initialization of entropy and formt of how we instantiate com…
rh0delta Sep 9, 2024
35eecee
Merge branch 'naynay/file-restructure' into naynay/accounts-restructure
rh0delta Sep 16, 2024
6951167
skipping faucet test for now, shenanigans occurring
rh0delta Sep 16, 2024
96d273c
fixed faucet test
rh0delta Sep 16, 2024
930d149
updated tests;
rh0delta Sep 16, 2024
6d0ea12
Update command.ts
rh0delta Sep 17, 2024
c941e17
pr review updates
rh0delta Sep 17, 2024
40774cc
Merge branch 'naynay/accounts-restructure' of https://github.com/entr…
rh0delta Sep 17, 2024
3e091f9
Update src/cli.ts
mixmix Sep 17, 2024
183e200
account-restructure tweaks (#226)
mixmix Sep 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Version header format: `[version] Name - year-month-day (entropy-core compatibil
- new: './src/transfer' - new file structure for our CLI/TUI flows
- new: './src/transfer/command.ts' - main entry file for transfer command for tui/cli
- new: './src/transfer/utils.ts' - utilities and helper methods for all things transfer
- new: './src/accounts' - new file structure for our CLI/TUI flows
- new: './src/accounts/command.ts' - main entry file for accounts command for tui/cli
- new: './src/accounts/utils.ts' - utilities and helper methods for all things accounts

### Changed

Expand All @@ -43,6 +46,8 @@ Version header format: `[version] Name - year-month-day (entropy-core compatibil
- merged user + dev program folders + tests
- removed flows/balance/*.ts directory with file restructure
- removed flows/entropyTransfer/*.ts directory with file restructure
- removed flows/manage-accounts/*/*.ts directory with file restructure
- removed flows/register/*.ts directory with file restructure


### Broke
Expand Down
105 changes: 105 additions & 0 deletions src/account/command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import Entropy from "@entropyxyz/sdk";
import { Command, Option } from 'commander'
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(accountCommand)
entropyAccountNew(accountCommand)
}

function entropyAccountNew (accountCommand: Command) {
accountCommand.command('create')
.alias('new')
.description('Create a new entropy account from scratch. Output is JSON of form {name, address}')
.addOption(endpointOption())
.addOption(passwordOption())
.argument('<name>', 'A user friendly name for your nem account.')
.addOption(
new Option(
'-p, --path',
'Derivation path'
).default(ACCOUNTS_CONTENT.path.default)
)
.action(async (name, opts) => {
const { endpoint, path } = opts

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 updateConfig(storedConfig, {
accounts,
selectedAccount: newAccount.address
})

cliWrite({
name: newAccount.name,
address: newAccount.address
})
process.exit(0)
})

}

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({ 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)
// })
mixmix marked this conversation as resolved.
Show resolved Hide resolved
36 changes: 36 additions & 0 deletions src/account/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export const FLOW_CONTEXT = 'ENTROPY_ACCOUNTS'

export const ACCOUNTS_CONTENT = {
seed: {
name: 'seed',
message: 'Enter seed:',
invalidSeed: 'Seed provided is not valid'
},
path: {
name: 'path',
message: 'derivation path:',
default: 'none',
},
importKey: {
name: 'importKey',
message: 'Would you like to import your own seed?',
default: false
},
name: {
name: 'name',
default: 'My Key',
},
selectAccount: {
name: "selectedAccount",
message: "Choose account:",
},
interactionChoice: {
name: 'interactionChoice',
choices: [
{ name: 'Create/Import Account', value: 'create-import' },
{ name: 'Select Account', value: 'select-account' },
{ name: 'List Accounts', value: 'list-account' },
{ name: 'Exit to Main Menu', value: 'exit' }
]
}
}
73 changes: 73 additions & 0 deletions src/account/interaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +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 {
manageAccountsQuestions,
newAccountQuestions,
selectAccountQuestions
} from "./utils"


export async function entropyManageAccounts (endpoint: string, storedConfig: EntropyConfig) {
mixmix marked this conversation as resolved.
Show resolved Hide resolved
const AccountService = new EntropyAccount({ endpoint })
const { accounts } = storedConfig
const { interactionChoice } = await inquirer.prompt(manageAccountsQuestions)
switch (interactionChoice) {
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]
}
const newAccount = await AccountService.create({ seed, name, path })
accounts.push(newAccount)
mixmix marked this conversation as resolved.
Show resolved Hide resolved
return {
accounts,
selectedAccount: newAccount.address
}
}
case 'select-account': {
const { selectedAccount } = await inquirer.prompt(selectAccountQuestions(accounts))

print('Current selected account is ' + selectedAccount)
return {
accounts: storedConfig.accounts,
selectedAccount: selectedAccount.address
}
}
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;
}
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 }
}
97 changes: 97 additions & 0 deletions src/account/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import Entropy from "@entropyxyz/sdk";
// @ts-expect-error
import Keyring from '@entropyxyz/sdk/keys'
import { randomAsHex } from '@polkadot/util-crypto'

import { EntropyBase } from "../common/entropy-base";
import { EntropyAccountConfig } from "../config/types";

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

export class EntropyAccount extends EntropyBase {
// 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> {
const keyring = new Keyring({ seed, path, debug: true })
const fullAccount = keyring.getAccount()
// TODO: sdk should create account on constructor
const { admin } = keyring.getAccount()

const data = fullAccount
delete admin.pair
// const encryptedData = password ? passwordFlow.encrypt(data, password) : data

return {
name: name,
address: admin.address,
data
// data: encryptedData // TODO: replace once password input is added back
}
}

list ({ accounts }: { accounts: EntropyAccountConfig[] }) {
const accountsArray = Array.isArray(accounts) && accounts.length
? accounts
: []
if (!accountsArray.length)
throw new Error(
'AccountsError: There are currently no accounts available, please create or import a new account using the Manage Accounts feature'
)
return formatAccountsList(accountsArray)
}

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
}
}

async registerAccount (account: EntropyAccountConfig, registerParams?: AccountRegisterParams): Promise<EntropyAccountConfig> {
rh0delta marked this conversation as resolved.
Show resolved Hide resolved
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
}
}
}
17 changes: 17 additions & 0 deletions src/account/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export interface AccountCreateParams {
name: string
seed?: string
path?: string
}

export type AccountListResults = {
name: string
address: string
verifyingKeys: string[]
}

export interface AccountRegisterParams {
programModAddress?: string
// TODO: Export ProgramInstance type from sdk
programData?: any
}
Loading
Loading