Skip to content

Commit

Permalink
Interface icx_closeoffer RPC (#400)
Browse files Browse the repository at this point in the history
* Added ICXOrderBook.closeOffer() function, testing and documentation

* Refactored code.

* Refactored code.

* Refactored code.

* Refactored code.
  • Loading branch information
surangap authored Jun 30, 2021
1 parent 479fbbe commit 6874e2a
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import { ContainerAdapterClient } from '../../container_adapter_client'
import { MasterNodeRegTestContainer } from '@defichain/testcontainers'
import { ICXGenericResult, ICXOfferInfo, ICXOrderInfo, ICXOffer, ICXOrder, UTXO, ICXOrderStatus } from '../../../src/category/icxorderbook'
import BigNumber from 'bignumber.js'
import { accountDFI, idDFI, accountBTC, ICXSetup, symbolDFI } from './icx_setup'
import { RpcApiError } from '../../../src'

describe('ICXOrderBook.closeOffer', () => {
const container = new MasterNodeRegTestContainer()
const client = new ContainerAdapterClient(container)
const icxSetup = new ICXSetup(container)

beforeAll(async () => {
await container.start()
await container.waitForReady()
await container.waitForWalletCoinbaseMaturity()
await icxSetup.createAccounts()
await icxSetup.createBTCToken()
await icxSetup.initializeTokensIds()
await icxSetup.mintBTCtoken(100)
await icxSetup.fundAccount(accountDFI, symbolDFI, 500)
await icxSetup.fundAccount(accountBTC, symbolDFI, 10) // for fee
await icxSetup.createBTCDFIPool()
await icxSetup.addLiquidityToBTCDFIPool(1, 100)
await icxSetup.setTakerFee(0.001)
})

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

it('should close an offer', async () => {
// create order - maker
const order: ICXOrder = {
tokenFrom: idDFI,
chainTo: 'BTC',
ownerAddress: accountDFI,
receivePubkey: '037f9563f30c609b19fd435a19b8bde7d6db703012ba1aba72e9f42a87366d1941',
amountFrom: new BigNumber(15),
orderPrice: new BigNumber(0.01)
}
const createOrderResult: ICXGenericResult = await client.icxorderbook.createOrder(order, [])
const createOrderTxId = createOrderResult.txid
await container.generate(1)

// list ICX orders and check status
const ordersAfterCreateOrder: Record<string, ICXOrderInfo | ICXOfferInfo> = await client.call('icx_listorders', [], 'bignumber')
expect((ordersAfterCreateOrder as Record<string, ICXOrderInfo>)[createOrderTxId].status).toStrictEqual(ICXOrderStatus.OPEN)

const accountBTCBeforeOffer: Record<string, BigNumber> = await client.call('getaccount', [accountBTC, {}, true], 'bignumber')
// make offer to partial amount 10 DFI - taker
const offer: ICXOffer = {
orderTx: createOrderTxId,
amount: new BigNumber(0.1), // 10 DFI = 0.1 BTC
ownerAddress: accountBTC
}
const makeOfferResult = await client.icxorderbook.makeOffer(offer, [])
const makeOfferTxId = makeOfferResult.txid
await container.generate(1)

const accountBTCAfterOffer: Record<string, BigNumber> = await client.call('getaccount', [accountBTC, {}, true], 'bignumber')
// check fee of 0.01 DFI has been reduced from the accountBTCBefore[idDFI]
// Fee = takerFeePerBTC(inBTC) * amount(inBTC) * DEX DFI per BTC rate
expect(accountBTCAfterOffer[idDFI]).toStrictEqual(accountBTCBeforeOffer[idDFI].minus(0.01))

// List the ICX offers for orderTx = createOrderTxId and check
const ordersAfterMakeOffer: Record<string, ICXOrderInfo | ICXOfferInfo> = await client.call('icx_listorders', [{ orderTx: createOrderTxId }], 'bignumber')
expect(Object.keys(ordersAfterMakeOffer).length).toBe(2) // extra entry for the warning text returned by the RPC atm.
expect((ordersAfterMakeOffer as Record<string, ICXOfferInfo>)[makeOfferTxId].status).toStrictEqual(ICXOrderStatus.OPEN)

// close offer makeOfferTxId - taker
await client.icxorderbook.closeOffer(makeOfferTxId)
await container.generate(1)

// List the ICX offers for orderTx = createOrderTxId and check no more offers
const ordersAfterCloseOffer: Record<string, ICXOrderInfo | ICXOfferInfo> = await await container.call('icx_listorders', [{ orderTx: createOrderTxId }])
expect(Object.keys(ordersAfterCloseOffer).length).toBe(1) // extra entry for the warning text returned by the RPC atm.

// check accountBTC balance, should be the same as accountBTCBeforeOffer
const accountBTCAfterOfferClose: Record<string, BigNumber> = await client.call('getaccount', [accountBTC, {}, true], 'bignumber')
expect(accountBTCAfterOfferClose).toStrictEqual(accountBTCBeforeOffer)
})

it('should close an offer with input utxos', async () => {
// create order - maker
const order: ICXOrder = {
tokenFrom: idDFI,
chainTo: 'BTC',
ownerAddress: accountDFI,
receivePubkey: '037f9563f30c609b19fd435a19b8bde7d6db703012ba1aba72e9f42a87366d1941',
amountFrom: new BigNumber(15),
orderPrice: new BigNumber(0.01)
}
const createOrderResult: ICXGenericResult = await client.icxorderbook.createOrder(order, [])
const createOrderTxId = createOrderResult.txid
await container.generate(1)

// list ICX orders
const ordersAfterCreateOrder: Record<string, ICXOrderInfo | ICXOfferInfo> = await client.call('icx_listorders', [], 'bignumber')
expect((ordersAfterCreateOrder as Record<string, ICXOrderInfo>)[createOrderTxId].status).toStrictEqual(ICXOrderStatus.OPEN)

const accountBTCBeforeOffer: Record<string, BigNumber> = await client.call('getaccount', [accountBTC, {}, true], 'bignumber')
// make offer to partial amount 10 DFI - taker
const offer: ICXOffer = {
orderTx: createOrderTxId,
amount: new BigNumber(0.1), // 10 DFI = 0.1 BTC
ownerAddress: accountBTC
}

const makeOfferResult = await client.icxorderbook.makeOffer(offer, [])
const makeOfferTxId = makeOfferResult.txid
await container.generate(1)

const accountBTCAfterOffer: Record<string, BigNumber> = await client.call('getaccount', [accountBTC, {}, true], 'bignumber')
// check fee of 0.01 DFI has been reduced from the accountBTCBefore[idDFI]
// Fee = takerFeePerBTC(inBTC) * amount(inBTC) * DEX DFI per BTC rate
expect(accountBTCAfterOffer[idDFI]).toStrictEqual(accountBTCBeforeOffer[idDFI].minus(0.01))

// List the ICX offers for orderTx = createOrderTxId and check
const ordersAfterMakeOffer: Record<string, ICXOrderInfo | ICXOfferInfo> = await client.call('icx_listorders', [{ orderTx: createOrderTxId }], 'bignumber')
expect(Object.keys(ordersAfterMakeOffer).length).toBe(2) // extra entry for the warning text returned by the RPC atm.
expect((ordersAfterMakeOffer as Record<string, ICXOfferInfo>)[makeOfferTxId].status).toStrictEqual(ICXOrderStatus.OPEN)

// input utxos
const utxos = await container.call('listunspent', [1, 9999999, [accountBTC], true])
const inputUTXOs: UTXO[] = utxos.map((utxo: UTXO) => {
return {
txid: utxo.txid,
vout: utxo.vout
}
})
// close offer makeOfferTxId - taker
await client.icxorderbook.closeOffer(makeOfferTxId, inputUTXOs)
await container.generate(1)

// List the ICX offers for orderTx = createOrderTxId and check no more offers
const ordersAfterCloseOffer: Record<string, ICXOrderInfo | ICXOfferInfo> = await client.call('icx_listorders', [{ orderTx: createOrderTxId }], 'bignumber')
expect(Object.keys(ordersAfterCloseOffer).length).toBe(1) // extra entry for the warning text returned by the RPC atm.

// check accountBTC balance, should be the same as accountBTCBeforeOffer
const accountBTCAfterOfferClose: Record<string, BigNumber> = await client.call('getaccount', [accountBTC, {}, true], 'bignumber')
expect(accountBTCAfterOfferClose).toStrictEqual(accountBTCBeforeOffer)
})

it('should return an error when incorrect offer transaction is passed', async () => {
// create order - maker
const order: ICXOrder = {
tokenFrom: idDFI,
chainTo: 'BTC',
ownerAddress: accountDFI,
receivePubkey: '037f9563f30c609b19fd435a19b8bde7d6db703012ba1aba72e9f42a87366d1941',
amountFrom: new BigNumber(15),
orderPrice: new BigNumber(0.01)
}
const createOrderResult: ICXGenericResult = await client.icxorderbook.createOrder(order, [])
const createOrderTxId = createOrderResult.txid
await container.generate(1)

// list ICX orders
const ordersAfterCreateOrder: Record<string, ICXOrderInfo | ICXOfferInfo> = await client.call('icx_listorders', [], 'bignumber')
expect((ordersAfterCreateOrder as Record<string, ICXOrderInfo>)[createOrderTxId].status).toStrictEqual(ICXOrderStatus.OPEN)

const accountBTCBeforeOffer: Record<string, BigNumber> = await client.call('getaccount', [accountBTC, {}, true], 'bignumber')
// make offer to partial amount 10 DFI - taker
const offer: ICXOffer = {
orderTx: createOrderTxId,
amount: new BigNumber(0.1), // 10 DFI = 0.1 BTC
ownerAddress: accountBTC
}

const makeOfferResult = await client.icxorderbook.makeOffer(offer, [])
const makeOfferTxId = makeOfferResult.txid
await container.generate(1)

const accountBTCAfterOffer: Record<string, BigNumber> = await client.call('getaccount', [accountBTC, {}, true], 'bignumber')
// check fee of 0.01 DFI has been reduced from the accountBTCBefore[idDFI]
// Fee = takerFeePerBTC(inBTC) * amount(inBTC) * DEX DFI per BTC rate
expect(accountBTCAfterOffer[idDFI]).toStrictEqual(accountBTCBeforeOffer[idDFI].minus(0.01))

// List the ICX offers for orderTx = createOrderTxId and check
const ordersAfterMakeOffer: Record<string, ICXOrderInfo | ICXOfferInfo> = await client.call('icx_listorders', [{ orderTx: createOrderTxId }], 'bignumber')
expect(Object.keys(ordersAfterMakeOffer).length).toBe(2) // extra entry for the warning text returned by the RPC atm.
expect((ordersAfterMakeOffer as Record<string, ICXOfferInfo>)[makeOfferTxId].status).toStrictEqual(ICXOrderStatus.OPEN)

// close offer "INVALID_OFFER_TX_ID" - taker
const promise = client.icxorderbook.closeOffer('INVALID_OFFER_TX_ID')

await expect(promise).rejects.toThrow(RpcApiError)
await expect(promise).rejects.toThrow('RpcApiError: \'OfferTx (0000000000000000000000000000000000000000000000000000000000000000) does not exist\', code: -8, method: icx_closeoffer')

// List the ICX offers for orderTx = createOrderTxId and check
const ordersAfterCloseOffer: Record<string, ICXOrderInfo | ICXOfferInfo> = await client.call('icx_listorders', [{ orderTx: createOrderTxId }], 'bignumber')
expect(Object.keys(ordersAfterCloseOffer).length).toBe(2) // extra entry for the warning text returned by the RPC atm.
})
})
21 changes: 20 additions & 1 deletion packages/jellyfish-api-core/src/category/icxorderbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class ICXOrderBook {
* @param {BigNumber} [offer.amountFrom] Amount fulfilling the order
* @param {string} [offer.ownerAddress] Address of DFI token and for receiving tokens in case of EXT/DFC order
* @param {string} [offer.receivePubkey] Pubkey which can claim external HTLC in case of EXT/DFC order type
* @param {number} [order.expiry] Number of blocks until the offer expires, default 10 DFI blocks
* @param {number} [order.expiry = 10] Number of blocks until the offer expires, default 10 DFI blocks
* @param {UTXO[]} [utxos = []] Specific utxos to spend
* @param {string} [utxos.txid] transaction Id
* @param {number} [utxos.vout] The output number
Expand All @@ -61,6 +61,25 @@ export class ICXOrderBook {
'bignumber'
)
}

/**
* Closes offer transaction.
*
* @param {string} offerTx Transaction Id of maker offer
* @param {UTXO[]} [utxos = []] Specific utxos to spend
* @param {string} [utxos.txid] transaction Id
* @param {number} [utxos.vout] The output number
* @return {Promise<ICXGenericResult>} Object indluding transaction id of the the transaction
*/
async closeOffer (offerTx: string, utxos: UTXO[] = []): Promise<ICXGenericResult> {
return await this.client.call(
'icx_closeoffer',
[
offerTx, utxos
],
'bignumber'
)
}
}
/** ICX order */
export interface ICXOrder {
Expand Down
20 changes: 20 additions & 0 deletions website/docs/jellyfish/api/icxorderbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,23 @@ interface ICXGenericResult {
txid: string
}
```

## closeOffer

Closes offer transaction.

```ts title="client.icxorderbook.closeOffer()"
interface icxorderbook {
closeOffer (offerTx: string, utxos: UTXO[] = []): Promise<ICXGenericResult>
}

interface UTXO {
txid: string
vout: number
}

interface ICXGenericResult {
WARNING: string
txid: string
}
```

0 comments on commit 6874e2a

Please sign in to comment.