From 33f117d3eac4d8df8e93e6e0cd615e772204eb47 Mon Sep 17 00:00:00 2001 From: frankie Date: Wed, 25 Sep 2024 12:37:16 -1000 Subject: [PATCH 1/2] wip - template --- src/account/main.ts | 11 +++++++--- src/config/index.ts | 2 +- src/template/command.ts | 42 +++++++++++++++++++++++++++++++++++++ src/template/constants.ts | 12 +++++++++++ src/template/interaction.ts | 16 ++++++++++++++ src/template/main.ts | 33 +++++++++++++++++++++++++++++ src/template/types.ts | 6 ++++++ src/template/utils.ts | 27 ++++++++++++++++++++++++ 8 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 src/template/command.ts create mode 100644 src/template/constants.ts create mode 100644 src/template/interaction.ts create mode 100644 src/template/main.ts create mode 100644 src/template/types.ts create mode 100644 src/template/utils.ts diff --git a/src/account/main.ts b/src/account/main.ts index 0c5d46d..750ee5a 100644 --- a/src/account/main.ts +++ b/src/account/main.ts @@ -24,11 +24,10 @@ export class EntropyAccount extends EntropyBase { await wasmGlobalsReady() const keyring = new Keyring({ seed, path, debug: true }) - const fullAccount = keyring.getAccount() + const data = keyring.getAccount() // TODO: sdk should create account on constructor - const { admin } = keyring.getAccount() + const { admin } = data - const data = fullAccount delete admin.pair // const encryptedData = password ? passwordFlow.encrypt(data, password) : data @@ -99,6 +98,12 @@ export class EntropyAccount extends EntropyBase { /* PRIVATE */ + /* + + WARNIG: this function needs to be removed in next core release [0.3.0]! + + */ + private async pruneRegistration () { return new Promise((resolve, reject) => { this.entropy.substrate.tx.registry.pruneRegistration() diff --git a/src/config/index.ts b/src/config/index.ts index 049b677..74774f7 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -68,7 +68,7 @@ export function getSync (configPath = CONFIG_PATH) { export async function set (config: EntropyConfig, configPath = CONFIG_PATH) { assertConfigPath(configPath) - + console.log('config spy: ', config) await mkdirp(dirname(configPath)) await writeFile(configPath, serialize(config)) } diff --git a/src/template/command.ts b/src/template/command.ts new file mode 100644 index 0000000..7c7f25c --- /dev/null +++ b/src/template/command.ts @@ -0,0 +1,42 @@ +import { Command } from "commander" +import { EntropyTemplate } from "./main" +import { cliWrite, accountOption, endpointOption, loadEntropy, passwordOption } from "../common/utils-cli"; + + +const command = { + name: 'transfer' + alias: [''] + description: 'Transfer funds between two Entropy accounts.' + // should be order + args: [ + {name: 'destination', description: 'Account address funds will be sent to'}, + {name: 'ammount', description: 'Amount of funds to be moved'}, + ], + optionFlags: [ + endpointOption + ], + +} + + +export function entropyTeplateCommand () { + const transferCommand = new Command('tranfer') + transferCommand + .description(command.description) // TODO: name the output + .argument('destination', 'Account address funds will be sent to') + .argument('amount', 'Amount of funds to be moved') + .addOption(passwordOption('Password for the source account (if required)')) + .addOption(endpointOption()) + .addOption(accountOption()) + .action(async (destination, amount, opts) => { + // load entropy + const entropy = await loadEntropy(opts.account, opts.endpoint) + // create service + const transferService = new EntropyTransfer(entropy, opts.endpoint) + // use sevice + await transferService.transfer(destination, amount) + // cliWrite(??) // TODO: write the output + process.exit(0) + }) + return transferCommand +} diff --git a/src/template/constants.ts b/src/template/constants.ts new file mode 100644 index 0000000..efcd865 --- /dev/null +++ b/src/template/constants.ts @@ -0,0 +1,12 @@ +export const PROMPT_CONTENT = { + amount: { + name: 'amount', + message: 'Input amount to transfer:', + default: '1', + invalidError: 'Please enter a value greater than 0', + }, + recipientAddress: { + name: 'recipientAddress', + message: `Input recipient's address:`, + }, +} \ No newline at end of file diff --git a/src/template/interaction.ts b/src/template/interaction.ts new file mode 100644 index 0000000..e0e4309 --- /dev/null +++ b/src/template/interaction.ts @@ -0,0 +1,16 @@ +import inquirer from "inquirer" +import { print } from "../common/utils" +import { EntropyTransfer } from "./main" +import { transferInputQuestions } from "./utils" +import { setupProgress } from "src/common/progress" + +export async function entropyTransfer (entropy, endpoint) { + const progressTracker = setupProgress('Transferring Funds') + const transferService = new EntropyTransfer(entropy, endpoint) + const { amount, recipientAddress } = await inquirer.prompt(transferInputQuestions) + await transferService.transfer(recipientAddress, amount, progressTracker) + print('') + print(`Transaction successful: Sent ${amount} to ${recipientAddress}`) + print('') + print('Press enter to return to main menu') +} diff --git a/src/template/main.ts b/src/template/main.ts new file mode 100644 index 0000000..8eec79e --- /dev/null +++ b/src/template/main.ts @@ -0,0 +1,33 @@ +import Entropy from "@entropyxyz/sdk"; +import { EntropyBase } from "../common/entropy-base"; + +/* + +This provides core functions that should be unit tested + +consumed by both ./command.ts and ./interaction.ts + +should follow a pattern of take in arguments return result with little side effects +in between NO PRINTING! + +atempt strict typeing + +*/ + + +// this is for logger context incase something fails and a user can provide a report +const FLOW_CONTEXT = 'ENTROPY_TEMPLATE' + +export class EntropyTemplate extends EntropyBase { + constructor (entropy: Entropy, endpoint: string) { + super({ entropy, endpoint, flowContext: FLOW_CONTEXT }) + } + + async mainExcutableFunction () { + // write code requireing the use of entropy! + } + + static async classMethod () { + // write stateless one-offs + } +} diff --git a/src/template/types.ts b/src/template/types.ts new file mode 100644 index 0000000..ec164f7 --- /dev/null +++ b/src/template/types.ts @@ -0,0 +1,6 @@ +// @ts-ignore +/* + +RECORD TYPES HERE + +*/ \ No newline at end of file diff --git a/src/template/utils.ts b/src/template/utils.ts new file mode 100644 index 0000000..d14ed76 --- /dev/null +++ b/src/template/utils.ts @@ -0,0 +1,27 @@ +import { TRANSFER_CONTENT } from "./constants"; + +function validateAmount (amount: string | number) { + if (isNaN(amount as number) || parseInt(amount as string) <= 0) { + return TRANSFER_CONTENT.amount.invalidError + } + return true +} + +const amountQuestion = { + type: 'input', + name: TRANSFER_CONTENT.amount.name, + message: TRANSFER_CONTENT.amount.message, + default: TRANSFER_CONTENT.amount.default, + validate: validateAmount +} + +const recipientAddressQuestion = { + type: 'input', + name: TRANSFER_CONTENT.recipientAddress.name, + message: TRANSFER_CONTENT.recipientAddress.message, +} + +export const transferInputQuestions = [ + amountQuestion, + recipientAddressQuestion +] \ No newline at end of file From c9d04ef09693ee1b0e0e927ae9483a2e7762f5f7 Mon Sep 17 00:00:00 2001 From: mixmix Date: Thu, 26 Sep 2024 16:54:41 +1200 Subject: [PATCH 2/2] wup --- src/README.md | 30 +++++++++ src/_template/README.md | 41 ++++++++++++ src/_template/command.ts | 84 ++++++++++++++++++++++++ src/{template => _template}/constants.ts | 4 +- src/_template/interaction.ts | 15 +++++ src/_template/main.ts | 58 ++++++++++++++++ src/{template => _template}/types.ts | 0 src/_template/utils.ts | 35 ++++++++++ src/account/constants.ts | 2 +- src/template/command.ts | 42 ------------ src/template/interaction.ts | 16 ----- src/template/main.ts | 33 ---------- src/template/utils.ts | 27 -------- 13 files changed, 266 insertions(+), 121 deletions(-) create mode 100644 src/README.md create mode 100644 src/_template/README.md create mode 100644 src/_template/command.ts rename src/{template => _template}/constants.ts (88%) create mode 100644 src/_template/interaction.ts create mode 100644 src/_template/main.ts rename src/{template => _template}/types.ts (100%) create mode 100644 src/_template/utils.ts delete mode 100644 src/template/command.ts delete mode 100644 src/template/interaction.ts delete mode 100644 src/template/main.ts delete mode 100644 src/template/utils.ts diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..6241628 --- /dev/null +++ b/src/README.md @@ -0,0 +1,30 @@ +# src/ docs + +- `src/cli.ts` - the entry-point for the application. Where all CLI and TUI + (text user interface) functions are registered. +- `src/tui.ts` - the entry-point for the TUI. + +## Special Folders + +- `src/_template/` - a template and guide for "User Flow" folders +- `src/common/` - helper functions used accross the application +- `src/config/` - utils for entropy config +- `src/types/` - types used across the application + +## "Domain" Folders + +CLI functionality is grouped into "domains". Within these we pool common +resources needed for programmatic CLI and TUI usage (see `src/_template/` for +detail) + +- `src/account/` - account creation, querying, manipulation etc. +- `src/balance/` - account balance querying +- `src/faucet/` - faucet functions for test-net +- `src/program/` - program deploying, querying, manipulation +- `src/sign/` - message signing +- `src/transfer/` - fund transfers + +### Legacy Folders + +- `src/flows` - a collection of functions leftover from an earier version + diff --git a/src/_template/README.md b/src/_template/README.md new file mode 100644 index 0000000..e51d7c1 --- /dev/null +++ b/src/_template/README.md @@ -0,0 +1,41 @@ +# Domain Template + +This folder described how we structure our "Domain" folders. + +```mermaid +flowchart + +direction TB + +entropy-base:::base + +subgraph example[ ] + direction TB + + types + main + command + interaction + + constants:::optional + utils:::optional + + main --> command & interaction +end + +entropy-base --> main + +classDef default fill:#B0B, stroke:none, color:#FFF; +classDef base fill:none, stroke:#000, color:#000; +classDef optional fill:#B9B, stroke:none; +classDef cluster fill:none, stroke:#B0B; +``` +_Diagram showing the required + optional files, and key dependencies._ + + +- `main.ts` - the core functions used by the flow (inherits from `EntropyBase`) +- `command.ts` - the programmatic CLI functions (depends on `main.ts`) +- `interactions.ts` - the TUI (text user interface) functions (depends on `main.ts`) +- `types.ts` - all the types/interfaces used in this flow +- `constants.ts` (optional) - constants used in this flow +- `utils.ts` (optional) - help function used in this flow diff --git a/src/_template/command.ts b/src/_template/command.ts new file mode 100644 index 0000000..3895f7e --- /dev/null +++ b/src/_template/command.ts @@ -0,0 +1,84 @@ +import { Command } from "commander" +import { EntropyDance } from "./main" +import { loadByteCode, loadDanceConfig } from "./utils" + +import { accountOption, endpointOption, loadEntropy, cliWrite } from "../common/utils-cli" + +/* + This file is responsible for building up the commands related to our domain + + There is a single export, which will be registered in src/cli.ts + This example has sub-commands (e.g. entropy dance learn), though not all do. + + The descriptions written here will be readable when users type e.g. + - entropy --help + - entropy dance --help + - entropy dance learn --help + + + ## References + + https://www.npmjs.com/package/commander + + + ## This example + + We use the made-up domain "dance" so we will have names like + - entropyDanceCommand + - entropyDanceLearn (for command: `entropy dance learn`) + +*/ + +export function entropyDanceCommand () { + return new Command('dance') + .description('Commands to query/ manipulate dances on the Entropy Network') + .addCommand(entropyDanceLearn()) + .addCommand(entropyDanceAdd()) +} + + +function entropyDanceLearn () { + return new Command('learn') + // description + .description('Have the Entropy network learn a new dance function.') + + // arguments + .argument('', 'the path to the bytecode being learnt') + + // options / flags + .addOption(accountOption()) + .addOption(endpointOption()) + + // what is run: + .action(async (byteCodePath, opts) => { + const danceMoveByteCode = await loadByteCode(byteCodePath) + const dance = new EntropyDance(opts.account, opts.endpoint) + + const pointer = await dance.learn(danceMoveByteCode) + + // We write output simply so other programs can parse + consume output + cliWrite(pointer) + + // NOTE: must exit the program! + process.exit(0) + }) +} + +function entropyDanceAdd () { + return new Command('add') + .description('Add a dance to your verifyingKey.') + .argument('', 'verifiying key to add the dance to') + .argument('', 'pointer for the dance bytecode that is already learn') + .argument('[danceConfigPath]', 'path to a config file for your dance') // optional + .addOption(accountOption()) + .addOption(endpointOption()) + .action(async (verifyingKey, dancePionter, danceConfigPath, opts) => { + const danceConfig = await loadDanceConfig(danceConfigPath) + const dance = new EntropyDance(opts.account, opts.endpoint) + + await dance.add(verifyingKey, dancePionter, danceConfig) + + // NOTE: must exit the program! + process.exit(0) + }) +} diff --git a/src/template/constants.ts b/src/_template/constants.ts similarity index 88% rename from src/template/constants.ts rename to src/_template/constants.ts index efcd865..45cd123 100644 --- a/src/template/constants.ts +++ b/src/_template/constants.ts @@ -1,4 +1,4 @@ -export const PROMPT_CONTENT = { +export const PROMPT = { amount: { name: 'amount', message: 'Input amount to transfer:', @@ -9,4 +9,4 @@ export const PROMPT_CONTENT = { name: 'recipientAddress', message: `Input recipient's address:`, }, -} \ No newline at end of file +} diff --git a/src/_template/interaction.ts b/src/_template/interaction.ts new file mode 100644 index 0000000..03888ed --- /dev/null +++ b/src/_template/interaction.ts @@ -0,0 +1,15 @@ +import inquirer from "inquirer" + +import { EntropyDance } from "./main" +import { danceInputQuestions } from "./utils" +import { print } from "../common/utils" + +export async function entropyTransfer (entropy, endpoint) { + const dance = new EntropyDance(entropy, endpoint) + + await dance.transfer(recipientAddress, amount, progressTracker) + print('') + print(`Transaction successful: Sent ${amount} to ${recipientAddress}`) + print('') + print('Press enter to return to main menu') +} diff --git a/src/_template/main.ts b/src/_template/main.ts new file mode 100644 index 0000000..b2d40b4 --- /dev/null +++ b/src/_template/main.ts @@ -0,0 +1,58 @@ +import Entropy from "@entropyxyz/sdk"; +import { EntropyBase } from "../common/entropy-base"; + +/* + + This file provides core functions consumed by both ./command.ts and ./interaction.ts + + ## Conventions + + 1. unit tested + 2. tight interface + - strict typing + - no this-or-that function signatures + 3. minimal side-effects + - ✓ logging + - ✓ substrate queries/ mutations + - ✗ config mutation + - ✗ printing + + + ## This example + + We use the made-up domain "dance" so we will have names like + - ENTROPY_DANCE + - EntropyDance + - dance = new EntropyDance(entroyp, endpoint) + - tests: tests/dance.test.ts + +*/ + + +// this is for logging output +const FLOW_CONTEXT = 'ENTROPY_DANCE' + +export class EntropyDance extends EntropyBase { + static isDanceMove (danceName: string) { + // stateless function - useful if you do not have/ need an entropy instance + // NOTE: no logging + return Boolean(danceName) + } + + constructor (entropy: Entropy, endpoint: string) { + super({ entropy, endpoint, flowContext: FLOW_CONTEXT }) + } + + async learn (danceMoveByteCode) { + // write code requiring the use of entropy + // + // return this.entropy... + } + + async add (verifyingKey, dancePointer, danceConfig) { + // .. + + // logging + this.logger.debug(`add: ${dancePointer} to ${verifyingKey}`, `${FLOW_CONTEXT}::add_dance`); + } +} diff --git a/src/template/types.ts b/src/_template/types.ts similarity index 100% rename from src/template/types.ts rename to src/_template/types.ts diff --git a/src/_template/utils.ts b/src/_template/utils.ts new file mode 100644 index 0000000..1364dad --- /dev/null +++ b/src/_template/utils.ts @@ -0,0 +1,35 @@ +import { PROMPT } from "./constants"; + +export async function loadByteCode (path) { + // TODO +} + +export async function loadDanceConfig (path) { + // TODO +} + +function validateAmount (amount: string | number) { + if (isNaN(amount as number) || parseInt(amount as string) <= 0) { + return PROMPT.amount.invalidError + } + return true +} + +const amountQuestion = { + type: 'input', + name: PROMPT.amount.name, + message: PROMPT.amount.message, + default: PROMPT.amount.default, + validate: validateAmount +} + +const recipientAddressQuestion = { + type: 'input', + name: PROMPT.recipientAddress.name, + message: PROMPT.recipientAddress.message, +} + +export const danceInputQuestions = [ + amountQuestion, + recipientAddressQuestion +] diff --git a/src/account/constants.ts b/src/account/constants.ts index 432c58d..20174a8 100644 --- a/src/account/constants.ts +++ b/src/account/constants.ts @@ -1,4 +1,4 @@ -export const FLOW_CONTEXT = 'ENTROPY_ACCOUNT' +export const FLOW_CONTEXT = 'ENTROPY_ACCOUNTS' export const ACCOUNTS_CONTENT = { seed: { diff --git a/src/template/command.ts b/src/template/command.ts deleted file mode 100644 index 7c7f25c..0000000 --- a/src/template/command.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Command } from "commander" -import { EntropyTemplate } from "./main" -import { cliWrite, accountOption, endpointOption, loadEntropy, passwordOption } from "../common/utils-cli"; - - -const command = { - name: 'transfer' - alias: [''] - description: 'Transfer funds between two Entropy accounts.' - // should be order - args: [ - {name: 'destination', description: 'Account address funds will be sent to'}, - {name: 'ammount', description: 'Amount of funds to be moved'}, - ], - optionFlags: [ - endpointOption - ], - -} - - -export function entropyTeplateCommand () { - const transferCommand = new Command('tranfer') - transferCommand - .description(command.description) // TODO: name the output - .argument('destination', 'Account address funds will be sent to') - .argument('amount', 'Amount of funds to be moved') - .addOption(passwordOption('Password for the source account (if required)')) - .addOption(endpointOption()) - .addOption(accountOption()) - .action(async (destination, amount, opts) => { - // load entropy - const entropy = await loadEntropy(opts.account, opts.endpoint) - // create service - const transferService = new EntropyTransfer(entropy, opts.endpoint) - // use sevice - await transferService.transfer(destination, amount) - // cliWrite(??) // TODO: write the output - process.exit(0) - }) - return transferCommand -} diff --git a/src/template/interaction.ts b/src/template/interaction.ts deleted file mode 100644 index e0e4309..0000000 --- a/src/template/interaction.ts +++ /dev/null @@ -1,16 +0,0 @@ -import inquirer from "inquirer" -import { print } from "../common/utils" -import { EntropyTransfer } from "./main" -import { transferInputQuestions } from "./utils" -import { setupProgress } from "src/common/progress" - -export async function entropyTransfer (entropy, endpoint) { - const progressTracker = setupProgress('Transferring Funds') - const transferService = new EntropyTransfer(entropy, endpoint) - const { amount, recipientAddress } = await inquirer.prompt(transferInputQuestions) - await transferService.transfer(recipientAddress, amount, progressTracker) - print('') - print(`Transaction successful: Sent ${amount} to ${recipientAddress}`) - print('') - print('Press enter to return to main menu') -} diff --git a/src/template/main.ts b/src/template/main.ts deleted file mode 100644 index 8eec79e..0000000 --- a/src/template/main.ts +++ /dev/null @@ -1,33 +0,0 @@ -import Entropy from "@entropyxyz/sdk"; -import { EntropyBase } from "../common/entropy-base"; - -/* - -This provides core functions that should be unit tested - -consumed by both ./command.ts and ./interaction.ts - -should follow a pattern of take in arguments return result with little side effects -in between NO PRINTING! - -atempt strict typeing - -*/ - - -// this is for logger context incase something fails and a user can provide a report -const FLOW_CONTEXT = 'ENTROPY_TEMPLATE' - -export class EntropyTemplate extends EntropyBase { - constructor (entropy: Entropy, endpoint: string) { - super({ entropy, endpoint, flowContext: FLOW_CONTEXT }) - } - - async mainExcutableFunction () { - // write code requireing the use of entropy! - } - - static async classMethod () { - // write stateless one-offs - } -} diff --git a/src/template/utils.ts b/src/template/utils.ts deleted file mode 100644 index d14ed76..0000000 --- a/src/template/utils.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TRANSFER_CONTENT } from "./constants"; - -function validateAmount (amount: string | number) { - if (isNaN(amount as number) || parseInt(amount as string) <= 0) { - return TRANSFER_CONTENT.amount.invalidError - } - return true -} - -const amountQuestion = { - type: 'input', - name: TRANSFER_CONTENT.amount.name, - message: TRANSFER_CONTENT.amount.message, - default: TRANSFER_CONTENT.amount.default, - validate: validateAmount -} - -const recipientAddressQuestion = { - type: 'input', - name: TRANSFER_CONTENT.recipientAddress.name, - message: TRANSFER_CONTENT.recipientAddress.message, -} - -export const transferInputQuestions = [ - amountQuestion, - recipientAddressQuestion -] \ No newline at end of file