Skip to content

Commit

Permalink
Merge pull request #329 from entropyxyz/naynay/substrate-overload
Browse files Browse the repository at this point in the history
[NayNay] Only substrate
  • Loading branch information
frankiebee authored Dec 19, 2024
2 parents 3223ce1 + 811cf73 commit b5089be
Show file tree
Hide file tree
Showing 14 changed files with 82 additions and 51 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/account/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/balance/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
}

Expand Down
2 changes: 1 addition & 1 deletion src/common/load-entropy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down
10 changes: 7 additions & 3 deletions src/common/substrate-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
5 changes: 2 additions & 3 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Entropy } from '@entropyxyz/sdk'
import { Buffer } from 'node:buffer'
import { homedir } from 'node:os'
import { join } from 'node:path'
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/faucet/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
20 changes: 13 additions & 7 deletions src/transfer/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -16,18 +18,22 @@ export function entropyTransferCommand () {
.addOption(endpointOption())
.action(async (destination, amount, opts) => {
// TODO: destination as <name|address> ?
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
Expand Down
18 changes: 13 additions & 5 deletions src/transfer/interaction.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
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}`)
print('')
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);
}
Expand Down
26 changes: 15 additions & 11 deletions src/transfer/main.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
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
// - setting `from`
// - 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<any> {
Expand All @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion src/tui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions tests/account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}


Expand Down
4 changes: 2 additions & 2 deletions tests/faucet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 }
}
Expand Down
35 changes: 22 additions & 13 deletions tests/transfer.test.ts
Original file line number Diff line number Diff line change
@@ -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)',
Expand All @@ -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
Expand All @@ -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()
})

0 comments on commit b5089be

Please sign in to comment.