Skip to content

Commit

Permalink
feat: new cli commands accounts:notes and accounts:transactions (i…
Browse files Browse the repository at this point in the history
…ron-fish#1086)

* new cli command - accounts:transactions

new cli command - accounts:transactions

* fix linting

* add assertHasAccount() in getTransactionNotes

* use variable 'account' instead of 'accountName'

* update code to latest version

* fix linting

* refactor: convert accounts:transactions -> accounts:notes

* refactor: getNotes type change

* feat: new accounts:transactions command

* fix: linting on test files

* make review changes

* fix test fail

* fix lint
  • Loading branch information
wd021 authored Jun 15, 2022
1 parent b6afbff commit 7441c21
Show file tree
Hide file tree
Showing 11 changed files with 738 additions and 0 deletions.
2 changes: 2 additions & 0 deletions ironfish-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ Interact with the node in a new terminal window:
- Request a small amount of $IRON for testing payments
- `yarn start accounts:pay`
- Send $IRON to another account
- `yarn start accounts:transactions [account]`
- Display transactions from and to your account

### Start a node and start mining
Run these commands in two different terminals:
Expand Down
59 changes: 59 additions & 0 deletions ironfish-cli/src/commands/accounts/notes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { GetAccountNotesResponse } from '@ironfish/sdk'
import { expect as expectCli, test } from '@oclif/test'

describe('accounts:notes', () => {
const responseContent: GetAccountNotesResponse = {
account: 'default',
notes: [
{
spender: true,
amount: 1,
memo: 'foo',
noteTxHash: '1fa5f38c446e52f8842d8c861507744fc3f354992610e1661e033ef316e2d3d1',
},
],
}

beforeAll(() => {
jest.doMock('@ironfish/sdk', () => {
const originalModule = jest.requireActual('@ironfish/sdk')
const client = {
connect: jest.fn(),
getAccountNotes: jest.fn().mockImplementation(() => ({
content: responseContent,
})),
}
const module: typeof jest = {
...originalModule,
IronfishSdk: {
init: jest.fn().mockImplementation(() => ({
connectRpc: jest.fn().mockResolvedValue(client),
client,
})),
},
}
return module
})
})

afterAll(() => {
jest.dontMock('@ironfish/sdk')
})

describe('fetching the notes for an account', () => {
test
.stdout()
.command(['accounts:notes', 'default'])
.exit(0)
.it('logs the notes for the given account', (ctx) => {
expectCli(ctx.stdout).include(responseContent.account)
expectCli(ctx.stdout).include(responseContent.notes[0].spender ? `✔` : `x`)
expectCli(ctx.stdout).include(responseContent.notes[0].amount)
expectCli(ctx.stdout).include(responseContent.notes[0].memo)
expectCli(ctx.stdout).include(responseContent.notes[0].noteTxHash)
})
})
})
56 changes: 56 additions & 0 deletions ironfish-cli/src/commands/accounts/notes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { oreToIron } from '@ironfish/sdk'
import { CliUx } from '@oclif/core'
import { IronfishCommand } from '../../command'
import { RemoteFlags } from '../../flags'

export class NotesCommand extends IronfishCommand {
static description = `Display the account notes`

static flags = {
...RemoteFlags,
}

static args = [
{
name: 'account',
parse: (input: string): Promise<string> => Promise.resolve(input.trim()),
required: false,
description: 'name of the account to get notes for',
},
]

async start(): Promise<void> {
const { args } = await this.parse(NotesCommand)
const account = args.account as string | undefined

const client = await this.sdk.connectRpc()

const response = await client.getAccountNotes({ account })

const { account: accountResponse, notes } = response.content

this.log(`\n ${accountResponse} - Account notes\n`)

CliUx.ux.table(notes, {
isSpender: {
header: 'Spender',
get: (row) => (row.spender ? `✔` : `x`),
},
amount: {
header: 'Amount ($IRON)',
get: (row) => oreToIron(row.amount),
},
memo: {
header: 'Memo',
},
noteTxHash: {
header: 'From Transaction',
},
})

this.log(`\n`)
}
}
121 changes: 121 additions & 0 deletions ironfish-cli/src/commands/accounts/transactions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { GetAccountTransactionResponse, GetAccountTransactionsResponse } from '@ironfish/sdk'
import { expect as expectCli, test } from '@oclif/test'

describe('accounts:transactions', () => {
const account = 'default'
const transactionHash = '1fa5f38c446e52f8842d8c861507744fc3f354992610e1661e033ef316e2d3d1'

const responseContentTransactions: GetAccountTransactionsResponse = {
account,
transactions: [
{
creator: true,
status: 'completed',
hash: '1fa5f38c446e52f8842d8c861507744fc3f354992610e1661e033ef316e2d3d1',
isMinersFee: false,
fee: 0.1,
notes: 1,
spends: 1,
},
],
}

const responseContentTransaction: GetAccountTransactionResponse = {
account,
transactionHash,
transactionInfo: {
status: 'completed',
isMinersFee: false,
fee: 0.1,
notes: 1,
spends: 1,
},
transactionNotes: [
{
spender: true,
amount: 1,
memo: 'foo',
},
],
}

beforeAll(() => {
jest.doMock('@ironfish/sdk', () => {
const originalModule = jest.requireActual('@ironfish/sdk')
const client = {
connect: jest.fn(),
getAccountTransactions: jest.fn().mockImplementation(() => ({
content: responseContentTransactions,
})),
getAccountTransaction: jest.fn().mockImplementation(() => ({
content: responseContentTransaction,
})),
}
const module: typeof jest = {
...originalModule,
IronfishSdk: {
init: jest.fn().mockImplementation(() => ({
connectRpc: jest.fn().mockResolvedValue(client),
client,
})),
},
}
return module
})
})

afterAll(() => {
jest.dontMock('@ironfish/sdk')
})

describe('fetching transactions for an account', () => {
test
.stdout()
.command(['accounts:transactions', `-a ${account}`])
.exit(0)
.it('logs the transactions for the given account', (ctx) => {
expectCli(ctx.stdout).include(responseContentTransactions.account)
expectCli(ctx.stdout).include(
responseContentTransactions.transactions[0].creator ? `✔` : `x`,
)
expectCli(ctx.stdout).include(responseContentTransactions.transactions[0].status)
expectCli(ctx.stdout).include(responseContentTransactions.transactions[0].hash)
expectCli(ctx.stdout).include(
responseContentTransactions.transactions[0].isMinersFee ? `✔` : `x`,
)
expectCli(ctx.stdout).include(responseContentTransactions.transactions[0].fee)
expectCli(ctx.stdout).include(responseContentTransactions.transactions[0].notes)
expectCli(ctx.stdout).include(responseContentTransactions.transactions[0].spends)
})
})

describe('fetching details of specific transaction', () => {
test
.stdout()
.command(['accounts:transactions', `-t ${transactionHash}`])
.exit(0)
.it('logs the transaction details and notes for the given hash', (ctx) => {
expectCli(ctx.stdout).include(responseContentTransaction.account)
expectCli(ctx.stdout).include(responseContentTransaction.transactionHash)

// transaction details
expectCli(ctx.stdout).include(responseContentTransaction.transactionInfo?.status)
expectCli(ctx.stdout).include(
responseContentTransaction.transactionInfo?.isMinersFee ? `✔` : `x`,
)
expectCli(ctx.stdout).include(responseContentTransaction.transactionInfo?.fee)
expectCli(ctx.stdout).include(responseContentTransaction.transactionInfo?.notes)
expectCli(ctx.stdout).include(responseContentTransaction.transactionInfo?.spends)

// transaction notes
expectCli(ctx.stdout).include(
responseContentTransaction.transactionNotes[0].spender ? `✔` : `x`,
)
expectCli(ctx.stdout).include(responseContentTransaction.transactionNotes[0].amount)
expectCli(ctx.stdout).include(responseContentTransaction.transactionNotes[0].memo)
})
})
})
117 changes: 117 additions & 0 deletions ironfish-cli/src/commands/accounts/transactions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { oreToIron } from '@ironfish/sdk'
import { CliUx, Flags } from '@oclif/core'
import { IronfishCommand } from '../../command'
import { RemoteFlags } from '../../flags'

export class TransactionsCommand extends IronfishCommand {
static description = `Display the account transactions`

static flags = {
...RemoteFlags,
account: Flags.string({
char: 'a',
description: 'account transactions',
}),
hash: Flags.string({
char: 't',
description: 'details of transaction hash',
}),
}

async start(): Promise<void> {
const { flags } = await this.parse(TransactionsCommand)
const account = flags.account?.trim()
const hash = flags.hash?.trim()

if (hash) {
await this.getTransaction(account, hash)
} else {
await this.getTransactions(account)
}
}

async getTransaction(account: string | undefined, hash: string): Promise<void> {
const client = await this.sdk.connectRpc()

const response = await client.getAccountTransaction({ account, hash })

const {
account: accountResponse,
transactionHash,
transactionInfo,
transactionNotes,
} = response.content

this.log(`Account: ${accountResponse}`)

if (transactionInfo !== null) {
this.log(
`Transaction: ${transactionHash}\nStatus: ${transactionInfo.status}\nMiner Fee: ${
transactionInfo.isMinersFee ? `✔` : `x`
}\nFee ($ORE): ${transactionInfo.fee}\nSpends: ${transactionInfo.spends}\n`,
)
}

if (transactionNotes.length > 0) {
this.log(`---Notes---\n`)

CliUx.ux.table(transactionNotes, {
isSpender: {
header: 'Spender',
get: (row) => (row.spender ? `✔` : `x`),
},
amount: {
header: 'Amount ($IRON)',
get: (row) => oreToIron(row.amount),
},
memo: {
header: 'Memo',
},
})
}

this.log(`\n`)
}

async getTransactions(account: string | undefined): Promise<void> {
const client = await this.sdk.connectRpc()

const response = await client.getAccountTransactions({ account })

const { account: accountResponse, transactions } = response.content

this.log(`\n ${String(accountResponse)} - Account transactions\n`)

CliUx.ux.table(transactions, {
status: {
header: 'Status',
},
creator: {
header: 'Creator',
get: (row) => (row.creator ? `✔` : `x`),
},
hash: {
header: 'Hash',
},
isMinersFee: {
header: 'Miner Fee',
get: (row) => (row.isMinersFee ? `✔` : `x`),
},
fee: {
header: 'Fee ($ORE)',
get: (row) => row.fee,
},
notes: {
header: 'Notes',
},
spends: {
header: 'Spends',
},
})

this.log(`\n`)
}
}
Loading

0 comments on commit 7441c21

Please sign in to comment.