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

Added listHtlcOutputs RPC #581

Merged
merged 3 commits into from
Aug 16, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { MasterNodeRegTestContainer } from '@defichain/testcontainers'
import { RpcApiError } from '@defichain/jellyfish-api-core'
import BigNumber from 'bignumber.js'
import { Testing } from '@defichain/jellyfish-testing'

describe('Spv', () => {
const testing = Testing.create(new MasterNodeRegTestContainer())

beforeAll(async () => {
await testing.container.start()
await testing.container.spv.fundAddress(await testing.rpc.spv.getNewAddress()) // Funds 1 BTC
})

afterAll(async () => {
await testing.container.stop()
})

it('should listHtlcOutputs', async () => {
surangap marked this conversation as resolved.
Show resolved Hide resolved
const pubKeyA = await testing.rpc.spv.getAddressPubKey(await testing.rpc.spv.getNewAddress())
const pubKeyB = await testing.rpc.spv.getAddressPubKey(await testing.rpc.spv.getNewAddress())
const timeout = 10
const seed = 'aba5f7e9aecf6ec4372c8a1e49562680d066da4655ee8b4bb01640479fffeaa8'
const seedhash = 'df95183883789f237977543885e1f82ddc045a3ba90c8f25b43a5b797a35d20e'

const htlc = await testing.rpc.spv.createHtlc(pubKeyA, pubKeyB, { timeout: `${timeout}`, seedhash })
await testing.container.generate(1)
const fund = await testing.rpc.spv.sendToAddress(htlc.address, new BigNumber(0.1)) // Funds HTLC address
const claim = await testing.rpc.spv.claimHtlc(
htlc.address,
await testing.rpc.spv.getNewAddress(),
{ seed }
)

const list = await testing.rpc.spv.listHtlcOutputs()
expect(list.length).toStrictEqual(1)
expect(list[0]).toStrictEqual({
txid: fund.txid,
vout: expect.any(Number),
amount: new BigNumber(0.1),
address: htlc.address,
confirms: 1,
spent: {
txid: claim.txid,
confirms: 1
}
})
})

it('listHtlcOutputs should return empty list when called with a non HTLC address', async () => {
const pubKeyA = await testing.rpc.spv.getAddressPubKey(await testing.rpc.spv.getNewAddress())
const pubKeyB = await testing.rpc.spv.getAddressPubKey(await testing.rpc.spv.getNewAddress())
const timeout = 10
const seed = 'aba5f7e9aecf6ec4372c8a1e49562680d066da4655ee8b4bb01640479fffeaa8'
const seedhash = 'df95183883789f237977543885e1f82ddc045a3ba90c8f25b43a5b797a35d20e'

const htlc = await testing.rpc.spv.createHtlc(pubKeyA, pubKeyB, { timeout: `${timeout}`, seedhash })
await testing.container.generate(1)
await testing.rpc.spv.sendToAddress(htlc.address, new BigNumber(0.1)) // Funds HTLC address
await testing.rpc.spv.claimHtlc(
htlc.address,
await testing.rpc.spv.getNewAddress(),
{ seed }
)

const list = await testing.rpc.spv.listHtlcOutputs(await testing.rpc.spv.getNewAddress())
expect(list.length).toStrictEqual(0)
})

it('should not listHtlcOutputs with invalid public address', async () => {
const promise = testing.rpc.spv.listHtlcOutputs('XXXX')

await expect(promise).rejects.toThrow(RpcApiError)
await expect(promise).rejects.toThrow("RpcApiError: 'Invalid address', code: -5, method: spv_listhtlcoutputs")
})
})

describe('Spv with multiple HTLC', () => {
const testing = Testing.create(new MasterNodeRegTestContainer())

beforeAll(async () => {
await testing.container.start()
await testing.container.spv.fundAddress(await testing.rpc.spv.getNewAddress()) // Funds 1 BTC
})

afterAll(async () => {
await testing.container.stop()
})

it('should listHtlcOutputs with multiple HTLC', async () => {
const pubKeyA = await testing.rpc.spv.getAddressPubKey(await testing.rpc.spv.getNewAddress())
const pubKeyB = await testing.rpc.spv.getAddressPubKey(await testing.rpc.spv.getNewAddress())
const timeout = 10
const seedhash = 'df95183883789f237977543885e1f82ddc045a3ba90c8f25b43a5b797a35d20e'

const htlc = await testing.rpc.spv.createHtlc(pubKeyA, pubKeyB, { timeout: `${timeout}`, seedhash })
const htlc2 = await testing.rpc.spv.createHtlc(pubKeyA, pubKeyB, { timeout: `${timeout}`, seedhash }) // Creates a second HTLC
await testing.container.generate(1)
const fund = await testing.rpc.spv.sendToAddress(htlc.address, new BigNumber(0.1)) // Funds HTLC address
const fund2 = await testing.rpc.spv.sendToAddress(htlc2.address, new BigNumber(0.1)) // Funds second HTLC address

const list = await testing.rpc.spv.listHtlcOutputs()
expect(list.length).toStrictEqual(2)
expect(list[0]).toStrictEqual({
txid: fund.txid,
vout: expect.any(Number),
amount: new BigNumber(0.1),
address: htlc.address,
confirms: 1
})
expect(list[1]).toStrictEqual({
txid: fund2.txid,
vout: expect.any(Number),
amount: new BigNumber(0.1),
address: htlc2.address,
confirms: 1
})
})

it('should listHtlcOutputs with specific HTLC address as filter', async () => {
const pubKeyA = await testing.rpc.spv.getAddressPubKey(await testing.rpc.spv.getNewAddress())
const pubKeyB = await testing.rpc.spv.getAddressPubKey(await testing.rpc.spv.getNewAddress())
const timeout = 10
const seed = 'aba5f7e9aecf6ec4372c8a1e49562680d066da4655ee8b4bb01640479fffeaa8'
const seedhash = 'df95183883789f237977543885e1f82ddc045a3ba90c8f25b43a5b797a35d20e'

const htlc = await testing.rpc.spv.createHtlc(pubKeyA, pubKeyB, { timeout: `${timeout}`, seedhash })
await testing.container.generate(1)
const fund = await testing.rpc.spv.sendToAddress(htlc.address, new BigNumber(0.1)) // Funds HTLC address
const claim = await testing.rpc.spv.claimHtlc(
htlc.address,
await testing.rpc.spv.getNewAddress(),
{ seed }
)

const list = await testing.rpc.spv.listHtlcOutputs(htlc.address)
expect(list.length).toStrictEqual(1)
expect(list[0]).toStrictEqual({
txid: fund.txid,
vout: expect.any(Number),
amount: new BigNumber(0.1),
address: htlc.address,
confirms: 1,
spent: {
txid: claim.txid,
confirms: 1
}
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ describe('Spv', () => {

beforeAll(async () => {
await container.start()
await container.waitForReady()

await container.spv.fundAddress(await container.call('spv_getnewaddress')) // Funds 1 BTC
})

Expand Down
32 changes: 32 additions & 0 deletions packages/jellyfish-api-core/src/category/spv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ export class Spv {
async refundHtlc (scriptAddress: string, destinationAddress: string, options: SpvDefaultOptions = { feeRate: new BigNumber('10000') }): Promise<SendMessageResult> {
return await this.client.call('spv_refundhtlc', [scriptAddress, destinationAddress, options.feeRate], 'number')
}

/**
* List all outputs related to HTLC addresses in the wallet.
*
* @param {string | undefined} [scriptAddress] HTLC address to filter result
* @return {Promise<ListHtlcsOutputsResult[]>}
*/
async listHtlcOutputs (scriptAddress?: string): Promise<ListHtlcsOutputsResult[]> {
return await this.client.call('spv_listhtlcoutputs', [scriptAddress], { amount: 'bignumber' })
}
}

export interface ReceivedByAddressInfo {
Expand Down Expand Up @@ -179,3 +189,25 @@ export interface ClaimHtlcOptions {
/** Fee rate in satoshis per KB */
feeRate?: BigNumber
}

export interface SpentInfo {
/** The transaction id */
txid: string
/** Number of spent confirmations */
confirms: number
}

export interface ListHtlcsOutputsResult {
/** The transaction id */
txid: string
/** Output relating to the HTLC address */
vout: number
/** Total amount of BTC recieved by the address */
amount: BigNumber
/** HTLC address */
address: string
/** Number of confirmations */
confirms: number
/** Object containing spent info */
spent: SpentInfo
}
24 changes: 24 additions & 0 deletions website/docs/jellyfish/api/spv.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,27 @@ interface SendMessageResult {
sendmessage: string
}
```

## listHtlcOutputs

List all outputs related to HTLC addresses in the wallet.

```ts title="client.spv.listHtlcOutputs()"
interface spv {
listHtlcOutputs (scriptAddress?: string): Promise<ListHtlcsOutputsResult[]>
}

interface SpentInfo {
txid: string
confirms: number
}

interface ListHtlcsOutputsResult {
txid: string
vout: number
amount: BigNumber
address: string
confirms: number
spent: SpentInfo
}
```