Skip to content
This repository has been archived by the owner on Jun 3, 2022. It is now read-only.

Add v0/:network/transactions/:id endpoint #244

Merged
merged 5 commits into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions packages/whale-api-client/__tests__/api/transaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,68 @@ describe('transaction', () => {
expect(feeRate).toStrictEqual(0.00005000)
})
})

describe('get', () => {
let txid: string

async function setup (): Promise<void> {
const address = await container.getNewAddress()
const metadata = {
symbol: 'ETH',
name: 'ETH',
isDAT: true,
mintable: true,
tradeable: true,
collateralAddress: address
}

txid = await container.call('createtoken', [metadata])

await container.generate(1)

const height = await container.call('getblockcount')

await service.waitForIndexedHeight(height)
}

beforeAll(async () => {
await setup()
})

it('should get a single transaction', async () => {
const transaction = await client.transactions.get(txid)
expect(transaction).toStrictEqual({
id: txid,
block: {
hash: expect.any(String),
height: expect.any(Number)
},
txid,
hash: txid,
version: expect.any(Number),
size: expect.any(Number),
vSize: expect.any(Number),
weight: expect.any(Number),
lockTime: expect.any(Number),
vinCount: expect.any(Number),
voutCount: expect.any(Number)
})
})

it('should fail due to non-existent transaction', async () => {
expect.assertions(2)
try {
await client.transactions.get('invalidtransactionid')
} catch (err) {
expect(err).toBeInstanceOf(WhaleApiException)
expect(err.error).toStrictEqual({
code: 404,
type: 'NotFound',
at: expect.any(Number),
message: 'Unable to find transaction by id: invalidtransactionid',
url: '/v0/regtest/transactions/invalidtransactionid'
})
}
})
})
})
28 changes: 28 additions & 0 deletions packages/whale-api-client/src/api/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export class Transactions {
return await this.client.requestData('POST', 'transactions', rawTx)
}

/**
* @param {string} id of transaction to query
* @return {Promise<Transaction>}
*/
async get (id: string): Promise<Transaction> {
return await this.client.requestData('GET', `transactions/${id}`)
}

/**
* @param {RawTxReq} rawTx to test mempool acceptance
* @throws WhaleApiException if failed mempool acceptance
Expand All @@ -36,3 +44,23 @@ export interface RawTxReq {
hex: string
maxFeeRate?: number
}

/**
* Transaction interface
*/
export interface Transaction {
id: string
block: {
hash: string
height: number
}
txid: string
hash: string
version: number
size: number
vSize: number
weight: number
lockTime: number
vinCount: number
voutCount: number
}
63 changes: 63 additions & 0 deletions src/module.api/transaction.controller.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { RegTest } from '@defichain/jellyfish-network'
import { BadRequestApiException } from '@src/module.api/_core/api.error'
import { NestFastifyApplication } from '@nestjs/platform-fastify'
import { createTestingApp, stopTestingApp, waitForIndexedHeight } from '@src/e2e.module'
import { NotFoundException } from '@nestjs/common'

describe('transactions', () => {
const container = new MasterNodeRegTestContainer()
Expand Down Expand Up @@ -172,4 +173,66 @@ describe('transactions', () => {
expect(after).not.toStrictEqual(0.00005000)
})
})

describe('get', () => {
let txid: string

async function setup (): Promise<void> {
const address = await container.getNewAddress()
const metadata = {
symbol: 'ETH',
name: 'ETH',
isDAT: true,
mintable: true,
tradeable: true,
collateralAddress: address
}

txid = await container.call('createtoken', [metadata])

await container.generate(1)

const height = await container.call('getblockcount')

await waitForIndexedHeight(app, height)
}

beforeAll(async () => {
await setup()
})

it('should get a single transaction', async () => {
const transaction = await controller.get(txid)
expect(transaction).toStrictEqual({
id: txid,
block: {
hash: expect.any(String),
height: expect.any(Number)
},
txid,
hash: expect.any(String),
siradji marked this conversation as resolved.
Show resolved Hide resolved
version: expect.any(Number),
size: expect.any(Number),
vSize: expect.any(Number),
weight: expect.any(Number),
lockTime: expect.any(Number),
vinCount: expect.any(Number),
voutCount: expect.any(Number)
})
})

it('should fail due to non-existent transaction', async () => {
expect.assertions(2)
try {
await controller.get('invalidtransactionid')
} catch (err) {
expect(err).toBeInstanceOf(NotFoundException)
expect(err.response).toStrictEqual({
statusCode: 404,
message: 'Unable to find transaction by id: invalidtransactionid',
error: 'Not Found'
})
}
})
})
})
13 changes: 12 additions & 1 deletion src/module.api/transaction.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { TransactionsController } from '@src/module.api/transaction.controller'
import { Bech32, Elliptic, HRP } from '@defichain/jellyfish-crypto'
import { RegTest } from '@defichain/jellyfish-network'
import { BadRequestApiException } from '@src/module.api/_core/api.error'
import { TransactionMapper } from '@src/module.model/transaction'
import { DatabaseModule } from '@src/module.database/_module'
import { ConfigModule } from '@nestjs/config'

describe('transactions', () => {
const container = new MasterNodeRegTestContainer()
Expand All @@ -25,10 +28,18 @@ describe('transactions', () => {

beforeEach(async () => {
await container.waitForWalletBalanceGTE(11)
const defidUrl = await container.getCachedRpcUrl()

const app: TestingModule = await Test.createTestingModule({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [() => ({ defid: { url: defidUrl } })]
}),
DatabaseModule.forRoot('memory')
],
controllers: [TransactionsController],
providers: [{ provide: JsonRpcClient, useValue: client }]
providers: [TransactionMapper, { provide: JsonRpcClient, useValue: client }]
}).compile()

controller = app.get<TransactionsController>(TransactionsController)
Expand Down
37 changes: 35 additions & 2 deletions src/module.api/transaction.controller.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import BigNumber from 'bignumber.js'
import { Body, Controller, Get, HttpCode, ParseIntPipe, Post, Query, ValidationPipe } from '@nestjs/common'
import {
Body,
Controller,
Get,
HttpCode,
ParseIntPipe,
Post,
Query,
ValidationPipe,
Param,
NotFoundException
} from '@nestjs/common'
import { JsonRpcClient } from '@defichain/jellyfish-api-jsonrpc'
import { IsHexadecimal, IsNotEmpty, IsNumber, IsOptional, Min } from 'class-validator'
import { BadRequestApiException } from '@src/module.api/_core/api.error'
import { EstimateMode } from '@defichain/jellyfish-api-core/dist/category/mining'
import { TransactionMapper } from '@src/module.model/transaction'
import { Transaction } from '@whale-api-client/api/transactions'

class RawTxDto {
@IsNotEmpty()
Expand All @@ -27,7 +40,10 @@ export class TransactionsController {
*/
private readonly defaultMaxFeeRate: BigNumber = new BigNumber('0.005')

constructor (private readonly client: JsonRpcClient) {
constructor (
private readonly client: JsonRpcClient,
private readonly transactionMapper: TransactionMapper
) {
}

/**
Expand All @@ -47,6 +63,23 @@ export class TransactionsController {
return 0.00005000
}

/**
* Get a single transaction by id
*
* @param {string} id of transaction to query
* @return{Promise<Transaction>}
*/
@Get('/:id')
async get (@Param('id') id: string): Promise<Transaction> {
const transaction = await this.transactionMapper.get(id)

if (transaction === undefined) {
throw new NotFoundException(`Unable to find transaction by id: ${id}`)
}

return transaction
}

/**
* @param {RawTxDto} tx to submit to the network.
* @return {Promise<string>} hash of the transaction
Expand Down