-
Notifications
You must be signed in to change notification settings - Fork 37
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
feat(jellyfish-api-core): add wallet.listtransactions RPC #2060
Open
andyrobert3
wants to merge
12
commits into
DeFiCh:main
Choose a base branch
from
andyrobert3:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
9b48200
chore: add documentation for listTransactions
andyrobert3 3a0f810
feat: add service logic for listTransactions
andyrobert3 bee26f5
chore: add test logic for listTransactions
andyrobert3 4c34de3
chore: remove irrelevant comment
andyrobert3 e407451
Merge branch 'main' into main
andyrobert3 05d3e5d
feat: Replace "listTransactions" parameters into object
andyrobert3 1e9b101
feat: Update tests to be more readable
andyrobert3 4e7c683
fix: Increase test case condition precision
andyrobert3 2c6113a
chore: Update tests to be more strict in equality comparison
andyrobert3 cb14e37
chore: Replace async for loop with Promise.all
andyrobert3 be68dea
fix: Update .md file for listTransactions
andyrobert3 530b5f6
Merge branch 'main' into main
andyrobert3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
230 changes: 230 additions & 0 deletions
230
packages/jellyfish-api-core/__tests__/category/wallet/listTransactions.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
import { BigNumber } from '@defichain/jellyfish-json' | ||
import { MasterNodeRegTestContainer } from '@defichain/testcontainers' | ||
import { ContainerAdapterClient } from '../../container_adapter_client' | ||
|
||
describe('listTransactions', () => { | ||
const container = new MasterNodeRegTestContainer() | ||
const client = new ContainerAdapterClient(container) | ||
|
||
const address = 'mwsZw8nF7pKxWH8eoKL9tPxTpaFkz7QeLU' | ||
|
||
beforeAll(async () => { | ||
await container.start() | ||
await container.waitForWalletCoinbaseMaturity() | ||
}) | ||
|
||
afterAll(async () => { | ||
await container.stop() | ||
}) | ||
|
||
it('should listTransactions', async () => { | ||
await Promise.all(Array.from({ length: 10 }).map(async (_, i) => { | ||
return await client.wallet.sendToAddress(address, 0.0001) | ||
})) | ||
await container.generate(1, address) | ||
|
||
const inWalletTransactions = await client.wallet.listTransactions({}) | ||
|
||
expect(inWalletTransactions.length).toStrictEqual(10) | ||
|
||
for (const inWalletTransaction of inWalletTransactions) { | ||
expect(inWalletTransaction).toMatchObject({ | ||
address: expect.any(String), | ||
txid: expect.any(String), | ||
amount: expect.any(BigNumber), | ||
confirmations: expect.any(Number), | ||
blockhash: expect.any(String), | ||
blocktime: expect.any(Number), | ||
blockindex: expect.any(Number), | ||
time: expect.any(Number), | ||
timereceived: expect.any(Number), | ||
// "bip125-replaceable" is "BIP125" enum but we test with "string" here | ||
'bip125-replaceable': expect.any(String), | ||
// "category" is "InWalletTransactionCategory" enum but we test with "string" here | ||
category: expect.any(String), | ||
label: expect.any(String), | ||
vout: expect.any(Number) | ||
}) | ||
} | ||
}) | ||
|
||
it('should listTransactions with label set', async () => { | ||
await Promise.all(Array.from({ length: 10 }).map(async (_, i) => { | ||
return await client.wallet.sendToAddress(address, 0.0001) | ||
})) | ||
await container.generate(1, address) | ||
|
||
const inWalletTransactions = await client.wallet.listTransactions({ label: 'owner' }) | ||
|
||
inWalletTransactions.forEach((inWalletTransaction) => { | ||
expect(inWalletTransaction.label).toStrictEqual('owner') | ||
}) | ||
|
||
expect(inWalletTransactions.length).toStrictEqual(10) | ||
|
||
for (const inWalletTransaction of inWalletTransactions) { | ||
expect(inWalletTransaction).toMatchObject({ | ||
address: expect.any(String), | ||
txid: expect.any(String), | ||
amount: expect.any(BigNumber), | ||
confirmations: expect.any(Number), | ||
blockhash: expect.any(String), | ||
blocktime: expect.any(Number), | ||
blockindex: expect.any(Number), | ||
time: expect.any(Number), | ||
timereceived: expect.any(Number), | ||
// "bip125-replaceable" is "BIP125" enum but we test with "string" here | ||
'bip125-replaceable': expect.any(String), | ||
// "category" is "InWalletTransactionCategory" enum but we test with "string" here | ||
category: expect.any(String), | ||
label: expect.any(String), | ||
vout: expect.any(Number) | ||
}) | ||
} | ||
}) | ||
|
||
it('should listTransactions with label set', async () => { | ||
await Promise.all(Array.from({ length: 10 }).map(async (_, i) => { | ||
return await client.wallet.sendToAddress(address, 0.0001) | ||
})) | ||
await container.generate(1, address) | ||
|
||
const inWalletTransactions = await client.wallet.listTransactions({ label: 'owner' }) | ||
|
||
inWalletTransactions.forEach((inWalletTransaction) => { | ||
expect(inWalletTransaction.label).toStrictEqual('owner') | ||
}) | ||
|
||
expect(inWalletTransactions.length).toStrictEqual(10) | ||
|
||
for (const inWalletTransaction of inWalletTransactions) { | ||
expect(inWalletTransaction).toMatchObject({ | ||
address: expect.any(String), | ||
txid: expect.any(String), | ||
amount: expect.any(BigNumber), | ||
confirmations: expect.any(Number), | ||
blockhash: expect.any(String), | ||
blocktime: expect.any(Number), | ||
blockindex: expect.any(Number), | ||
time: expect.any(Number), | ||
timereceived: expect.any(Number), | ||
// "bip125-replaceable" is "BIP125" enum but we test with "string" here | ||
'bip125-replaceable': expect.any(String), | ||
// "category" is "InWalletTransactionCategory" enum but we test with "string" here | ||
category: expect.any(String), | ||
label: expect.any(String), | ||
vout: expect.any(Number) | ||
}) | ||
} | ||
}) | ||
|
||
it('should listTransactions with count = 5', async () => { | ||
await Promise.all(Array.from({ length: 5 }).map(async (_, i) => { | ||
return await client.wallet.sendToAddress(address, 0.0001) | ||
})) | ||
await container.generate(1, address) | ||
|
||
const inWalletTransactions = await client.wallet.listTransactions({ count: 5 }) | ||
|
||
expect(inWalletTransactions.length).toStrictEqual(5) | ||
|
||
for (const inWalletTransaction of inWalletTransactions) { | ||
expect(inWalletTransaction).toMatchObject({ | ||
address: expect.any(String), | ||
txid: expect.any(String), | ||
amount: expect.any(BigNumber), | ||
confirmations: expect.any(Number), | ||
blockhash: expect.any(String), | ||
blocktime: expect.any(Number), | ||
blockindex: expect.any(Number), | ||
time: expect.any(Number), | ||
timereceived: expect.any(Number), | ||
// "bip125-replaceable" is "BIP125" enum but we test with "string" here | ||
'bip125-replaceable': expect.any(String), | ||
// "category" is "InWalletTransactionCategory" enum but we test with "string" here | ||
category: expect.any(String), | ||
label: expect.any(String), | ||
vout: expect.any(Number) | ||
}) | ||
} | ||
}) | ||
|
||
it('should not listTransactions with count = -1', async () => { | ||
await expect(client.wallet.listTransactions({ count: -1 })).rejects.toThrow('RpcApiError: \'Negative count\', code: -8, method: listtransactions') | ||
}) | ||
|
||
it('should listTransactions with count = 0', async () => { | ||
const inWalletTransactions = await client.wallet.listTransactions({ count: 0 }) | ||
expect(inWalletTransactions.length).toStrictEqual(0) | ||
}) | ||
|
||
it('should listTransactions with includeWatchOnly false', async () => { | ||
await Promise.all(Array.from({ length: 10 }).map(async (_, i) => { | ||
return await client.wallet.sendToAddress(address, 0.0001) | ||
})) | ||
await container.generate(1, address) | ||
|
||
const inWalletTransactions = await client.wallet.listTransactions({ includeWatchOnly: false }) | ||
|
||
inWalletTransactions.forEach((inWalletTransaction) => { | ||
expect(inWalletTransaction.address).toStrictEqual(address) | ||
}) | ||
|
||
expect(inWalletTransactions.length).toStrictEqual(10) | ||
|
||
for (const inWalletTransaction of inWalletTransactions) { | ||
expect(inWalletTransaction).toMatchObject({ | ||
address: expect.any(String), | ||
txid: expect.any(String), | ||
amount: expect.any(BigNumber), | ||
confirmations: expect.any(Number), | ||
blockhash: expect.any(String), | ||
blocktime: expect.any(Number), | ||
blockindex: expect.any(Number), | ||
time: expect.any(Number), | ||
timereceived: expect.any(Number), | ||
// "bip125-replaceable" is "BIP125" enum but we test with "string" here | ||
'bip125-replaceable': expect.any(String), | ||
// "category" is "InWalletTransactionCategory" enum but we test with "string" here | ||
category: expect.any(String), | ||
label: expect.any(String), | ||
vout: expect.any(Number) | ||
}) | ||
} | ||
}) | ||
|
||
it('should listTransactions with excludeCustomTx = true', async () => { | ||
await Promise.all(Array.from({ length: 10 }).map(async (_, i) => { | ||
return await client.wallet.sendToAddress(address, 0.0001) | ||
})) | ||
await container.generate(1, address) | ||
|
||
const inWalletTransactions = await client.wallet.listTransactions({ excludeCustomTx: true }) | ||
|
||
inWalletTransactions.forEach((inWalletTransaction) => { | ||
expect(inWalletTransaction.address).toStrictEqual(address) | ||
}) | ||
|
||
expect(inWalletTransactions.length).toStrictEqual(10) | ||
|
||
for (const inWalletTransaction of inWalletTransactions) { | ||
expect(inWalletTransaction).toMatchObject({ | ||
address: expect.any(String), | ||
txid: expect.any(String), | ||
amount: expect.any(BigNumber), | ||
confirmations: expect.any(Number), | ||
blockhash: expect.any(String), | ||
blocktime: expect.any(Number), | ||
blockindex: expect.any(Number), | ||
time: expect.any(Number), | ||
timereceived: expect.any(Number), | ||
// "bip125-replaceable" is "BIP125" enum but we test with "string" here | ||
'bip125-replaceable': expect.any(String), | ||
// "category" is "InWalletTransactionCategory" enum but we test with "string" here | ||
category: expect.any(String), | ||
label: expect.any(String), | ||
vout: expect.any(Number) | ||
}) | ||
} | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why we prefer
toMatchObject
here overtoStrictEqual
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are the specifications on what attributes are returned by the
listtransactions
function on DeFiChainhttps://github.com/DeFiCh/ain/blob/master/src/wallet/rpcwallet.cpp
When running the tests, sometimes there are additional optional returned parameters that are not included in the specifications above:
generated
-> booleanwalletconflicts
-> ArrayThese parameters appear in some responses, and not others.
Using
toStrictEqual
may fail tests here, the extra parametersgenerated
&walletconflicts
are not always included in the response.However,
toMatchObject
is defined as "check that a JavaScript object matches a subset of the properties of an object"In this case, we can just compare the response result if it matches a subset of the specification parameters from the DeFiChain repository
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If anyone from the DeFi chain team knows when & why the 2 extra parameters appear, feel free to add on here so I can modify my tests to use
toStrictEqual
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah okay that makes sense
I guess the RPC doc needs updating in
ain
thenThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you know who should i ask here? @eli-lim
I'll probably raise a ticket to the
ain
repo?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, just raise a ticket
In the mean time, let's wait for others to review this PR