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] Transfer updates + unit testing #140

Merged
merged 9 commits into from
Jul 3, 2024
18 changes: 14 additions & 4 deletions src/common/initializeEntropy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import inquirer from "inquirer"
import { decrypt, encrypt } from "../flows/password"
import { debug } from "../common/utils"
import * as config from "../config"
import { EntropyAccountData } from "../types"
import { EntropyAccountData } from "../config/types"

// TODO: unused
// let defaultAccount // have a main account to use
Expand All @@ -17,8 +17,18 @@ const keyrings = {
default: undefined // this is the "selected account" keyring
}

export function getKeyring (address) {
if (!address && keyrings.default) return keyrings.default
export function getKeyring (address?: string, seed?: string) {
rh0delta marked this conversation as resolved.
Show resolved Hide resolved

if (!address && !seed && keyrings.default) return keyrings.default
if (!address && seed && keyrings.default && Object.keys(keyrings).length > 1) {
const [keyring] = Object.keys(keyrings)
.filter(kr => {

return keyrings[kr]?.admin?.seed === seed
})

return keyring
}
if (address && keyrings[address]) return keyrings[address]
// explicitly return undefined so there is no confusion around what is selected
return undefined
Expand Down Expand Up @@ -65,7 +75,7 @@ export const initializeEntropy = async ({ keyMaterial, password, endpoint, confi
}

let selectedAccount
const storedKeyring = getKeyring(accountData?.admin?.address)
const storedKeyring = getKeyring(accountData?.admin?.address, accountData.seed)

if(!storedKeyring) {
const keyring = new Keyring({ ...accountData, debug: true })
Expand Down
2 changes: 1 addition & 1 deletion src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { decodeAddress, encodeAddress } from "@polkadot/keyring"
import { hexToU8a, isHex } from "@polkadot/util"
import { Buffer } from 'buffer'
import Debug from 'debug'
import { EntropyAccountConfig } from "../types"
import { EntropyAccountConfig } from "../config/types"

const _debug = Debug('@entropyxyz/cli')

Expand Down
2 changes: 1 addition & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import envPaths from 'env-paths'

import allMigrations from './migrations'

const paths = envPaths('entropyxyz', { suffix: '' })
const paths = envPaths('entropy-cryptography', { suffix: '' })
rh0delta marked this conversation as resolved.
Show resolved Hide resolved
const CONFIG_PATH = join(paths.config, 'entropy-cli.json')
const OLD_CONFIG_PATH = join(process.env.HOME, '.entropy-cli.config')

Expand Down
36 changes: 36 additions & 0 deletions src/config/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export interface EntropyConfig {
accounts: EntropyAccountConfig[]
endpoints: { dev: string; 'test-net': string }
'migration-version': string
}

export interface EntropyAccountConfig {
name: string
address: string
data: EntropyAccountData
}

export interface EntropyAccountData {
debug?: boolean
seed: string
admin?: EntropyAccount
registration?: EntropyAccount
deviceKey?: EntropyAccount
programDev?: EntropyAccount
}

export interface EntropyAccount {
seed: string
path: string
address: string
verifyingKeys?: string[]
userContext?: EntropyAccountContextType
used?: boolean
}

export enum EntropyAccountContextType {
programDev = 'PROGRAM_DEV_KEY',
registration = 'ADMIN_KEY',
deviceKey = 'CONSUMER_KEY',
undefined = 'MIXED_KEY',
}
63 changes: 29 additions & 34 deletions src/flows/entropyTransfer/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import inquirer from "inquirer"
import cliProgress from 'cli-progress'
import colors from 'ansi-colors'

import { print, getSelectedAccount } from "../../common/utils"
import { getSelectedAccount, print } from "../../common/utils"
import { initializeEntropy } from "../../common/initializeEntropy"
import { transfer } from "./transfer"

const question = [
{
Expand All @@ -29,53 +29,48 @@ export async function entropyTransfer ({ accounts, selectedAccount: selectedAcco
const { endpoint } = options
const selectedAccount = getSelectedAccount(accounts, selectedAccountAddress)

const b1 = new cliProgress.SingleBar({
format: 'Transferring Funds |' + colors.cyan('{bar}') + '| {percentage}%',
barCompleteChar: '\u2588',
barIncompleteChar: '\u2591',
hideCursor: true
})

try {
const entropy = await initializeEntropy({
keyMaterial: selectedAccount.data,
endpoint
})

const b1 = new cliProgress.SingleBar({
format: 'Transferring Funds |' + colors.cyan('{bar}') + '| {percentage}%',
barCompleteChar: '\u2588',
barIncompleteChar: '\u2591',
hideCursor: true
})

const { amount, recipientAddress } = await inquirer.prompt(question)

if (!entropy?.keyring?.accounts?.registration?.pair) {
throw new Error("Signer keypair is undefined or not properly initialized.")
}
const formattedAmount = BigInt(parseInt(amount) * 1e10)
const tx = await entropy.substrate.tx.balances.transferAllowDeath(
recipientAddress,
BigInt(formattedAmount),
b1.start(300, 0, {
speed: "N/A"
})
// update values
const interval = setInterval(() => {
b1.increment()
}, 100)
await transfer(
entropy,
{
from: entropy.keyring.accounts.registration.pair,
to: recipientAddress,
amount: formattedAmount
}
)
b1.stop()
clearInterval(interval)
rh0delta marked this conversation as resolved.
Show resolved Hide resolved

await tx.signAndSend (entropy.keyring.accounts.registration.pair, ({ status }) => {
// initialize the bar - defining payload token "speed" with the default value "N/A"
b1.start(300, 0, {
speed: "N/A"
});
// update values
const interval = setInterval(() => {
b1.increment()
}, 100)
if (status.isFinalized) {
b1.stop()
clearInterval(interval)
print(
`\nTransaction successful: Sent ${amount} to ${recipientAddress}`
)
print('\nPress enter to return to main menu');
}
})
return;

print(
`\nTransaction successful: Sent ${amount} to ${recipientAddress}`
)
print('\nPress enter to return to main menu')
} catch (error) {
console.error('ERR:::', error);


}
}
34 changes: 34 additions & 0 deletions src/flows/entropyTransfer/transfer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Entropy from "@entropyxyz/sdk";
import { TransferOptions } from "./types";

export async function transfer (entropy: Entropy, payload: TransferOptions) {
const { from, to, amount } = payload
rh0delta marked this conversation as resolved.
Show resolved Hide resolved

return new Promise((resolve, reject) => {
// WARN: await signAndSend is dangerous as it does not resolve
// after transaction is complete :melt:
entropy.substrate.tx.balances
.transferAllowDeath(to, amount)
// @ts-ignore
.signAndSend(from, ({ status, dispatchError }) => {
if (dispatchError) {
let msg: string
if (dispatchError.isModule) {
// for module errors, we have the section indexed, lookup
const decoded = entropy.substrate.registry.findMetaError(
dispatchError.asModule
)
const { docs, name, section } = decoded

msg = `${section}.${name}: ${docs.join(' ')}`
} else {
// Other, CannotLookup, BadOrigin, no extra info
msg = dispatchError.toString()
}
return reject(Error(msg))
}

if (status.isFinalized) resolve(status)
})
})
}
5 changes: 5 additions & 0 deletions src/flows/entropyTransfer/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface TransferOptions {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍

from?: any
to: string
amount: number | string | bigint
}
36 changes: 0 additions & 36 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,3 @@
export interface EntropyConfig {
accounts: EntropyAccountConfig[]
endpoints: { dev: string; 'test-net': string }
'migration-version': string
}
export interface EntropyAccountConfig {
name: string
address: string
data: EntropyAccountData
}

export interface EntropyAccountData {
debug?: boolean
seed: string
admin?: EntropyAccount
registration?: EntropyAccount
deviceKey?: EntropyAccount
programDev?: EntropyAccount
}

export interface EntropyAccount {
seed: string
path: string
address: string
verifyingKeys?: string[]
userContext?: EntropyAccountContextType
used?: boolean
}

export enum EntropyAccountContextType {
programDev = 'PROGRAM_DEV_KEY',
registration = 'ADMIN_KEY',
deviceKey = 'CONSUMER_KEY',
undefined = 'MIXED_KEY',
}

export interface EntropyTuiOptions {
dev: boolean
endpoint: string
Expand Down
2 changes: 1 addition & 1 deletion tests/manage-accounts.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EntropyAccountConfig, EntropyConfig } from 'src/types'
import { EntropyAccountConfig, EntropyConfig } from 'src/config/types'
import test from 'tape'
import { charlieStashAddress, charlieStashSeed } from './testing-utils/constants'
import { listAccounts } from 'src/flows/manage-accounts/list'
Expand Down
82 changes: 82 additions & 0 deletions tests/transfer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import test from 'tape'
import Entropy, { wasmGlobalsReady } from '@entropyxyz/sdk'
// WIP: I'm seeing problems importing this?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it resolved in the SDK that is un-published yet I wonder

import Keyring from '@entropyxyz/sdk/dist/keys/index'
import {
makeSeed,
promiseRunner,
sleep,
spinNetworkUp,
spinNetworkDown
} from './testing-utils'

import { getBalance } from '../src/flows/balance/balance'
import { initializeEntropy } from 'src/common/initializeEntropy'
import { charlieStashAddress, charlieStashSeed } from './testing-utils/constants'
import { transfer } from 'src/flows/entropyTransfer/transfer'

const networkType = 'two-nodes'

test('Transfer', async (t) => {
/* Setup */
const run = promiseRunner(t)
await run('wasm', wasmGlobalsReady())
await run('network up', spinNetworkUp(networkType))
// this gets called after all tests are run
t.teardown(async () => {
await entropy.close()
await charlieEntropy.close()
await spinNetworkDown(networkType).catch((error) =>
console.error('Error while spinning network down', error.message)
)
})
await sleep(process.env.GITHUB_WORKSPACE ? 30_000 : 5_000)

const naynaySeed = makeSeed()
const entropy = await initializeEntropy({ keyMaterial: { seed: naynaySeed, debug: true }, endpoint: 'ws://127.0.0.1:9944', })
const charlieEntropy = await initializeEntropy({ keyMaterial: { seed: charlieStashSeed, debug: true }, endpoint: 'ws://127.0.0.1:9944', })
await run('entropy ready', entropy.ready)
await run('charlie ready', charlieEntropy.ready)

const recipientAddress = entropy.keyring.accounts.registration.address

// Check Balance of new account
let naynayBalance = await run(
'getBalance (naynay)',
getBalance(entropy, recipientAddress)
)

t.equal(naynayBalance, 0, 'naynay is broke')

let charlieBalance = await run(
'getBalance (charlieStash)',
getBalance(entropy, charlieStashAddress)
)

t.equal(charlieBalance, 1e21, 'charlie got bank')
rh0delta marked this conversation as resolved.
Show resolved Hide resolved

try {
const transferStatus = await transfer(
entropy,
{
from: charlieEntropy.keyring.accounts.registration.pair,
to: recipientAddress,
amount: BigInt(1000 * 10e10)
}
)
// @ts-ignore
t.true(transferStatus.isFinalized, 'Funds transferred successfully')
} catch (error) {
console.error('error', error);
}
rh0delta marked this conversation as resolved.
Show resolved Hide resolved

// Re-Check Balance of new account
naynayBalance = await run(
'getBalance (naynay)',
getBalance(entropy, recipientAddress)
)

t.equal(naynayBalance, 1000 * 10e10, 'naynay is rolling in it!')

t.end()
})