diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d3df9e..cf21949 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ Version header format: `[version] Name - year-month-day (entropy-core compatibil - Shared - updated return data displayed to user on account creation (create or import) [#311](https://github.com/entropyxyz/cli/pull/311) - Balance now displays the number of BITS to the nearest 4 decimal places [#306](https://github.com/entropyxyz/cli/pull/306) + - removed use of entropy instance from transfer flow [#329](https://github.com/entropyxyz/cli/pull/329) - CLI - updated balance command to take in any address, and be able to return the balance for the inputted address [#315](https://github.com/entropyxyz/cli/pull/315) diff --git a/src/account/utils.ts b/src/account/utils.ts index 206babf..55b849d 100644 --- a/src/account/utils.ts +++ b/src/account/utils.ts @@ -32,7 +32,7 @@ export async function persistVerifyingKeyToAccount (configPath: string, verifyin const storedConfig = await config.get(configPath) const { accounts } = storedConfig - const account = findAccountByAddressOrName(accounts, accountNameOrAddress || storedConfig.selectedAccount) + const account = findAccountByAddressOrName(accounts, accountNameOrAddress) if (!account) throw Error(`Unable to persist verifyingKey "${verifyingKey}" to unknown account "${accountNameOrAddress}"`) // persist to config, set selectedAccount diff --git a/src/balance/main.ts b/src/balance/main.ts index 1f5d3bf..8b1d379 100644 --- a/src/balance/main.ts +++ b/src/balance/main.ts @@ -4,7 +4,7 @@ import { EntropySubstrateBase } from "src/common/entropy-substrate-base" const FLOW_CONTEXT = 'ENTROPY-BALANCE' export class EntropyBalance extends EntropySubstrateBase { - constructor (substrate, endpoint) { + constructor (substrate: any, endpoint: string) { super({ substrate, endpoint, flowContext: FLOW_CONTEXT }) } diff --git a/src/common/load-entropy.ts b/src/common/load-entropy.ts index fdd77f8..0abc1a8 100644 --- a/src/common/load-entropy.ts +++ b/src/common/load-entropy.ts @@ -211,7 +211,7 @@ async function setupRegistrationSubAccount (account: EntropyConfigAccount, confi } const keyringCache = {} -async function loadKeyring (account: EntropyConfigAccount) { +export async function loadKeyring (account: EntropyConfigAccount) { const { address } = account.data.admin || {} if (!address) throw new Error('Cannot load keyring, no admin address') diff --git a/src/common/substrate-utils.ts b/src/common/substrate-utils.ts index 1796901..9d5ef1a 100644 --- a/src/common/substrate-utils.ts +++ b/src/common/substrate-utils.ts @@ -8,7 +8,11 @@ export async function getLoadedSubstrate (endpoint: string) { } export async function closeSubstrate (substrate: any) { - // closing substrate - return await substrate.disconnect() - .catch(err => console.error('Error closing connection', err.message)) + try { + // closing substrate + await substrate.disconnect() + } catch (error) { + console.error('SubstrateError: Error closing connection', error) + throw error + } } \ No newline at end of file diff --git a/src/common/utils.ts b/src/common/utils.ts index 8017439..86f6738 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -1,4 +1,3 @@ -import { Entropy } from '@entropyxyz/sdk' import { Buffer } from 'node:buffer' import { homedir } from 'node:os' import { join } from 'node:path' @@ -111,11 +110,11 @@ export function absolutePath (somePath: string) { } } -export function formatDispatchError (entropy: Entropy, dispatchError) { +export function formatDispatchError (substrate: any, dispatchError) { let msg: string if (dispatchError.isModule) { // for module errors, we have the section indexed, lookup - const decoded = entropy.substrate.registry.findMetaError( + const decoded = substrate.registry.findMetaError( dispatchError.asModule ) const { docs, name, section } = decoded diff --git a/src/faucet/main.ts b/src/faucet/main.ts index dbd3d6b..a196927 100644 --- a/src/faucet/main.ts +++ b/src/faucet/main.ts @@ -34,7 +34,7 @@ export class EntropyFaucet extends EntropyBase { // status would still be set, but in the case of error we can shortcut // to just check it (so an error would indicate InBlock or Finalized) if (dispatchError) { - const error = formatDispatchError(this.entropy, dispatchError) + const error = formatDispatchError(this.entropy.substrate, dispatchError) return reject(error) } if (status.isFinalized) resolve(status) diff --git a/src/transfer/command.ts b/src/transfer/command.ts index a5f1173..20a3016 100644 --- a/src/transfer/command.ts +++ b/src/transfer/command.ts @@ -2,8 +2,10 @@ import { Command } from "commander" import { EntropyTransfer } from "./main" import { accountOption, configOption, endpointOption, cliWrite } from "../common/utils-cli" -import { loadEntropyCli } from "../common/load-entropy" -import { getTokenDetails } from "../common/utils" +import { loadKeyring } from "../common/load-entropy" +import { findAccountByAddressOrName, getTokenDetails } from "../common/utils" +import * as config from "../config"; +import { closeSubstrate, getLoadedSubstrate } from "src/common/substrate-utils" export function entropyTransferCommand () { const transferCommand = new Command('transfer') @@ -16,18 +18,22 @@ export function entropyTransferCommand () { .addOption(endpointOption()) .action(async (destination, amount, opts) => { // TODO: destination as ? - const entropy = await loadEntropyCli(opts) - const transferService = new EntropyTransfer(entropy, opts.endpoint) - const { symbol } = await getTokenDetails(entropy.substrate) + const { accounts, selectedAccount } = await config.get(opts.config) + const substrate = await getLoadedSubstrate(opts.endpoint) + const account = findAccountByAddressOrName(accounts, opts.account || selectedAccount) + const loadedKeyring = await loadKeyring(account) + const transferService = new EntropyTransfer(substrate, opts.endpoint) + const { symbol } = await getTokenDetails(substrate) - await transferService.transfer(destination, amount) + await transferService.transfer(loadedKeyring.accounts.registration.pair, destination, amount) cliWrite({ - source: entropy.keyring.accounts.registration.address, + source: loadedKeyring.accounts.registration.address, destination, amount, symbol }) + await closeSubstrate(substrate) process.exit(0) }) return transferCommand diff --git a/src/transfer/interaction.ts b/src/transfer/interaction.ts index 4d32134..f199d98 100644 --- a/src/transfer/interaction.ts +++ b/src/transfer/interaction.ts @@ -1,24 +1,31 @@ import inquirer from "inquirer" import yoctoSpinner from "yocto-spinner" -import { getTokenDetails, print } from "../common/utils" +import { findAccountByAddressOrName, getTokenDetails, print } from "../common/utils" import { EntropyTransfer } from "./main" import { transferInputQuestions } from "./utils" import { EntropyTuiOptions } from '../types' +import { EntropyConfig } from "src/config/types" +import { closeSubstrate, getLoadedSubstrate } from "src/common/substrate-utils" +import { loadKeyring } from "src/common/load-entropy" const transferSpinner = yoctoSpinner() const SPINNER_TEXT = 'Transferring funds...' -export async function entropyTransfer (entropy, opts: EntropyTuiOptions) { +export async function entropyTransfer (opts: EntropyTuiOptions, storedConfig: EntropyConfig) { transferSpinner.text = SPINNER_TEXT if (transferSpinner.isSpinning) transferSpinner.stop() try { - const { symbol } = await getTokenDetails(entropy.substrate) - const transferService = new EntropyTransfer(entropy, opts.endpoint) + const substrate = await getLoadedSubstrate(opts.endpoint) + const currentAccount = findAccountByAddressOrName(storedConfig.accounts, opts.account || storedConfig.selectedAccount) + const loadedKeyring = await loadKeyring(currentAccount) + const { symbol } = await getTokenDetails(substrate) + const transferService = new EntropyTransfer(substrate, opts.endpoint) const { amount, recipientAddress } = await inquirer.prompt(transferInputQuestions) if (!transferSpinner.isSpinning) transferSpinner.start() - await transferService.transfer(recipientAddress, amount) + await transferService.transfer(loadedKeyring.accounts.registration.pair, recipientAddress, amount) + await closeSubstrate(opts.endpoint) if (transferSpinner.isSpinning) transferSpinner.stop() print('') print(`Transaction successful: Sent ${amount} ${symbol} to ${recipientAddress}`) @@ -26,6 +33,7 @@ export async function entropyTransfer (entropy, opts: EntropyTuiOptions) { print('Press enter to return to main menu') } catch (error) { transferSpinner.text = 'Transfer failed...' + await closeSubstrate(opts.endpoint) if (transferSpinner.isSpinning) transferSpinner.stop() print.error('TransferError:', error.message); } diff --git a/src/transfer/main.ts b/src/transfer/main.ts index a22f035..61968b3 100644 --- a/src/transfer/main.ts +++ b/src/transfer/main.ts @@ -1,14 +1,16 @@ -import Entropy from "@entropyxyz/sdk"; +// @ts-ignore +import { Pair } from '@entropyxyz/sdk/keys' -import { EntropyBase } from "../common/entropy-base"; import { bitsToLilBits, formatDispatchError, getTokenDetails } from "../common/utils"; + import { TransferOptions } from "./types"; +import { EntropySubstrateBase } from 'src/common/entropy-substrate-base'; const FLOW_CONTEXT = 'ENTROPY_TRANSFER' -export class EntropyTransfer extends EntropyBase { - constructor (entropy: Entropy, endpoint: string) { - super({ entropy, endpoint, flowContext: FLOW_CONTEXT }) +export class EntropyTransfer extends EntropySubstrateBase { + constructor (substrate: any, endpoint: string) { + super({ substrate, endpoint, flowContext: FLOW_CONTEXT }) } // NOTE: a more accessible function which handles @@ -16,15 +18,17 @@ export class EntropyTransfer extends EntropyBase { // - converting `amount` (string => BigInt) // - progress callbacks (optional) - async transfer (toAddress: string, amountInBits: string) { - const { decimals } = await getTokenDetails(this.entropy.substrate) + async transfer (from: Pair, toAddress: string, amountInBits: string) { + const { decimals } = await getTokenDetails(this.substrate) const lilBits = bitsToLilBits(Number(amountInBits), decimals) - return this.rawTransfer({ - from: this.entropy.keyring.accounts.registration.pair, + const transferStatus = await this.rawTransfer({ + from, to: toAddress, lilBits }) + + return transferStatus } private async rawTransfer (payload: TransferOptions): Promise { @@ -33,12 +37,12 @@ export class EntropyTransfer extends EntropyBase { return new Promise((resolve, reject) => { // WARN: await signAndSend is dangerous as it does not resolve // after transaction is complete :melt: - this.entropy.substrate.tx.balances + this.substrate.tx.balances .transferAllowDeath(to, lilBits) // @ts-ignore .signAndSend(from, ({ status, dispatchError }) => { if (dispatchError) { - const error = formatDispatchError(this.entropy, dispatchError) + const error = formatDispatchError(this.substrate, dispatchError) this.logger.error('There was an issue sending this transfer', error) return reject(error) } diff --git a/src/tui.ts b/src/tui.ts index cd87604..01b208e 100644 --- a/src/tui.ts +++ b/src/tui.ts @@ -160,7 +160,7 @@ async function main (entropy: Entropy, choices: string[], opts: EntropyTuiOption break } case 'Transfer': { - await entropyTransfer(entropy, opts) + await entropyTransfer(opts, storedConfig) .catch(err => console.error('There was an error sending the transfer', err)) break } diff --git a/tests/account.test.ts b/tests/account.test.ts index eb41c2a..c12a0a6 100644 --- a/tests/account.test.ts +++ b/tests/account.test.ts @@ -84,9 +84,9 @@ const endpoint = 'ws://127.0.0.1:9944' async function fundAccount (t, entropy: Entropy) { const { entropy: charlie } = await setupTest(t, { seed: charlieStashSeed }) - const transfer = new EntropyTransfer(charlie, endpoint) + const transfer = new EntropyTransfer(charlie.substrate, endpoint) - await transfer.transfer(entropy.keyring.accounts.registration.address, "1000") + await transfer.transfer(charlie.keyring.accounts.registration.pair, entropy.keyring.accounts.registration.address, "1000") } diff --git a/tests/faucet.test.ts b/tests/faucet.test.ts index b6bb9b7..94a8ca1 100644 --- a/tests/faucet.test.ts +++ b/tests/faucet.test.ts @@ -13,7 +13,7 @@ async function setupAndFundFaucet (t) { const { run, entropy, endpoint } = await setupTest(t, { seed: eveSeed }) const account = new EntropyAccount(entropy, endpoint) - const transfer = new EntropyTransfer(entropy, endpoint) + const transfer = new EntropyTransfer(entropy.substrate, endpoint) const faucet = new EntropyFaucet(entropy, endpoint) // Deploy faucet program @@ -65,7 +65,7 @@ async function setupAndFundFaucet (t) { const verifyingKeys = await faucet.getAllFaucetVerifyingKeys(eveAddress) // @ts-expect-error const { chosenVerifyingKey, faucetAddress } = faucet.getRandomFaucet([], verifyingKeys) - await run('Transfer funds to faucet address', transfer.transfer(faucetAddress, "1000")) + await run('Transfer funds to faucet address', transfer.transfer(entropy.keyring.accounts.registration.pair, faucetAddress, "1000")) return { faucetProgramPointer, chosenVerifyingKey, faucetAddress } } diff --git a/tests/transfer.test.ts b/tests/transfer.test.ts index 822f561..ad4f65f 100644 --- a/tests/transfer.test.ts +++ b/tests/transfer.test.ts @@ -1,21 +1,30 @@ import test from 'tape' +import { randomAsHex } from '@polkadot/util-crypto' +import Keyring from '@entropyxyz/sdk/keys'; -import { lilBitsPerBits } from "../src/common/utils"; -import { EntropyTransfer } from '../src/transfer/main' +import { EntropyAccount } from '../src/account/main' import { EntropyBalance } from '../src/balance/main' -import { promiseRunner, setupTest } from './testing-utils' +import { closeSubstrate, getLoadedSubstrate } from '../src/common/substrate-utils' +import { lilBitsPerBits } from "../src/common/utils" +import { EntropyTransfer } from '../src/transfer/main' + +import { setupTest } from './testing-utils' import { charlieStashAddress, charlieStashSeed, DEFAULT_TOKEN_DECIMALS } from './testing-utils/constants.mjs' test('Transfer', async (t) => { /* Setup */ - const { run, entropy: charlie, endpoint }= await setupTest(t, { seed: charlieStashSeed }) - const { entropy: naynay } = await setupTest(t) - - const transferService = new EntropyTransfer(charlie, endpoint) - const BalanceService = new EntropyBalance(charlie.substrate, endpoint) - - const naynayAddress = naynay.keyring.accounts.registration.address - + const testAccountSeed = randomAsHex(32) + const testAccountName = 'Test Account' + const naynay = await EntropyAccount.import({ name: testAccountName, seed: testAccountSeed }) + + // setuptest still needed to run here to start up wasm and get the config ready + const { run, endpoint }= await setupTest(t, { seed: charlieStashSeed }) + const substrate = await run('load substrate', getLoadedSubstrate(endpoint)) + const transferService = new EntropyTransfer(substrate, endpoint) + const BalanceService = new EntropyBalance(substrate, endpoint) + + const naynayAddress = naynay.address + const charlieKeyring = new Keyring({ seed: charlieStashSeed, path: '', debug: true }) // Check initial balances let naynayBalance = await run( 'getBalance (naynay)', @@ -33,7 +42,7 @@ test('Transfer', async (t) => { const inputAmount = "1.5" await run( 'transfer', - transferService.transfer(naynayAddress, inputAmount) + transferService.transfer(charlieKeyring.accounts.registration.pair, naynayAddress, inputAmount) ) // Re-Check balance @@ -43,6 +52,6 @@ test('Transfer', async (t) => { ) const expected = Number(inputAmount) * lilBitsPerBits(DEFAULT_TOKEN_DECIMALS) t.equal(naynayBalance, expected, 'naynay is rolling in it!') - + await run('closeSubstrate', closeSubstrate(substrate)) t.end() })