Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/src/hooks/__tests__/useBCH.test.js
/* eslint-disable no-native-reassign */ | /* eslint-disable no-native-reassign */ | ||||
import useBCH from '../useBCH'; | import useBCH from '../useBCH'; | ||||
import mockReturnGetUtxos from '../__mocks__/mockReturnGetUtxos'; | import mockReturnGetUtxos from '../__mocks__/mockReturnGetUtxos'; | ||||
import mockReturnGetHydratedUtxoDetails from '../__mocks__/mockReturnGetHydratedUtxoDetails'; | import mockReturnGetHydratedUtxoDetails from '../__mocks__/mockReturnGetHydratedUtxoDetails'; | ||||
import mockReturnGetSlpBalancesAndUtxos from '../__mocks__/mockReturnGetSlpBalancesAndUtxos'; | import mockReturnGetSlpBalancesAndUtxos from '../__mocks__/mockReturnGetSlpBalancesAndUtxos'; | ||||
import sendBCHMock from '../__mocks__/sendBCH'; | import sendBCHMock from '../__mocks__/sendBCH'; | ||||
import BCHJS from '@psf/bch-js'; // TODO: should be removed when external lib not needed anymore | import BCHJS from '@psf/bch-js'; // TODO: should be removed when external lib not needed anymore | ||||
import { currency } from '../../components/Common/Ticker'; | import { currency, feeLevels } from '../../components/Common/Ticker'; | ||||
import sendBCH from '../__mocks__/sendBCH'; | import sendBCH from '../__mocks__/sendBCH'; | ||||
import BigNumber from 'bignumber.js'; | import BigNumber from 'bignumber.js'; | ||||
// Determine constants that depend on Cashtab fee setting | |||||
let mockPointer; | |||||
switch (currency.defaultFee) { | |||||
case feeLevels.minimum: | |||||
mockPointer = 'minimum'; | |||||
break; | |||||
case feeLevels.normal: | |||||
mockPointer = 'normal'; | |||||
break; | |||||
case feeLevels.express: | |||||
mockPointer = 'express'; | |||||
break; | |||||
case feeLevels.ludicrous: | |||||
mockPointer = 'ludicrous'; | |||||
break; | |||||
default: | |||||
mockPointer = 'normal'; | |||||
} | |||||
const { | |||||
expectedHex, | |||||
expectedOneOutputFee, | |||||
expectedTwoOutputFee, | |||||
} = sendBCHMock.expectedFeeOutputs[mockPointer]; | |||||
describe('useBCH hook', () => { | describe('useBCH hook', () => { | ||||
it('gets Rest Api Url on testnet', () => { | it('gets Rest Api Url on testnet', () => { | ||||
process = { | process = { | ||||
env: { | env: { | ||||
REACT_APP_NETWORK: `testnet`, | REACT_APP_NETWORK: `testnet`, | ||||
REACT_APP_BCHA_APIS: | REACT_APP_BCHA_APIS: | ||||
'https://rest.kingbch.com/v3/,https://wallet-service-prod.bitframe.org/v3/,notevenaurl,https://rest.kingbch.com/v3/', | 'https://rest.kingbch.com/v3/,https://wallet-service-prod.bitframe.org/v3/,notevenaurl,https://rest.kingbch.com/v3/', | ||||
REACT_APP_BCHA_APIS_TEST: | REACT_APP_BCHA_APIS_TEST: | ||||
Show All 17 Lines | it('gets primary Rest API URL on mainnet', () => { | ||||
const expectedApiUrl = `https://rest.kingbch.com/v3/`; | const expectedApiUrl = `https://rest.kingbch.com/v3/`; | ||||
expect(getRestUrl(0)).toBe(expectedApiUrl); | expect(getRestUrl(0)).toBe(expectedApiUrl); | ||||
}); | }); | ||||
it('calculates fee correctly for 2 P2PKH outputs', () => { | it('calculates fee correctly for 2 P2PKH outputs', () => { | ||||
const { calcFee } = useBCH(); | const { calcFee } = useBCH(); | ||||
const BCH = new BCHJS(); | const BCH = new BCHJS(); | ||||
const utxosMock = [{}, {}]; | const utxosMock = [{}, {}]; | ||||
// For 1.01 sat/byte fee | |||||
let expectedTxFee = 378; | expect(calcFee(BCH, utxosMock)).toBe(expectedTwoOutputFee); | ||||
if (currency.defaultFee === 3.01) { | }); | ||||
expectedTxFee = 1126; | |||||
} else if (currency.defaultFee === 5.01) { | it('calculates fee correctly for 1 P2PKH output', () => { | ||||
expectedTxFee = 1874; | const { calcFee } = useBCH(); | ||||
} else if ((currency.defaultFee = 83.3)) { | const BCH = new BCHJS(); | ||||
expectedTxFee = 31155; | const utxosMock = [{}]; | ||||
} | |||||
expect(calcFee(BCH, utxosMock)).toBe(expectedTxFee); | expect(calcFee(BCH, utxosMock)).toBe(expectedOneOutputFee); | ||||
}); | }); | ||||
it('gets SLP and BCH balances and utxos from hydrated utxo details', async () => { | it('gets SLP and BCH balances and utxos from hydrated utxo details', async () => { | ||||
const { getSlpBalancesAndUtxos } = useBCH(); | const { getSlpBalancesAndUtxos } = useBCH(); | ||||
const result = await getSlpBalancesAndUtxos( | const result = await getSlpBalancesAndUtxos( | ||||
mockReturnGetHydratedUtxoDetails, | mockReturnGetHydratedUtxoDetails, | ||||
); | ); | ||||
expect(result).toStrictEqual(mockReturnGetSlpBalancesAndUtxos); | expect(result).toStrictEqual(mockReturnGetSlpBalancesAndUtxos); | ||||
}); | }); | ||||
it('sends BCH correctly', async () => { | it('sends BCH correctly', async () => { | ||||
const { sendBch } = useBCH(); | const { sendBch } = useBCH(); | ||||
const BCH = new BCHJS(); | const BCH = new BCHJS(); | ||||
const { | const { expectedTxId, utxos, wallet, addresses, values } = sendBCHMock; | ||||
expectedTxId, | |||||
expectedHex, | |||||
utxos, | |||||
wallet, | |||||
addresses, | |||||
values, | |||||
} = sendBCHMock; | |||||
let expectedHexByFee = expectedHex; | |||||
if (currency.defaultFee === 3.01) { | |||||
expectedHexByFee = sendBCHMock.expectedHexThreeSatPerByteFee; | |||||
} else if (currency.defaultFee === 5.01) { | |||||
expectedHexByFee = sendBCHMock.expectedHexFiveSatPerByteFee; | |||||
} else if (currency.defaultFee === 83.3) { | |||||
expectedHexByFee = sendBCHMock.expectedHexEightyThreeSatPerByteFee; | |||||
} | |||||
BCH.RawTransactions.sendRawTransaction = jest | BCH.RawTransactions.sendRawTransaction = jest | ||||
.fn() | .fn() | ||||
.mockResolvedValue(expectedTxId); | .mockResolvedValue(expectedTxId); | ||||
expect(await sendBch(BCH, wallet, utxos, { addresses, values })).toBe( | expect(await sendBch(BCH, wallet, utxos, { addresses, values })).toBe( | ||||
`${currency.blockExplorerUrl}/tx/${expectedTxId}`, | `${currency.blockExplorerUrl}/tx/${expectedTxId}`, | ||||
); | ); | ||||
expect(BCH.RawTransactions.sendRawTransaction).toHaveBeenCalledWith( | expect(BCH.RawTransactions.sendRawTransaction).toHaveBeenCalledWith( | ||||
expectedHexByFee, | expectedHex, | ||||
); | ); | ||||
}); | }); | ||||
it('sends BCH correctly with callback', async () => { | it('sends BCH correctly with callback', async () => { | ||||
const { sendBch } = useBCH(); | const { sendBch } = useBCH(); | ||||
const BCH = new BCHJS(); | const BCH = new BCHJS(); | ||||
const callback = jest.fn(); | const callback = jest.fn(); | ||||
const { | const { expectedTxId, utxos, wallet, addresses, values } = sendBCHMock; | ||||
expectedTxId, | |||||
expectedHex, | |||||
utxos, | |||||
wallet, | |||||
addresses, | |||||
values, | |||||
} = sendBCHMock; | |||||
let expectedHexByFee = expectedHex; | |||||
if (currency.defaultFee === 3.01) { | |||||
expectedHexByFee = sendBCHMock.expectedHexThreeSatPerByteFee; | |||||
} else if (currency.defaultFee === 5.01) { | |||||
expectedHexByFee = sendBCHMock.expectedHexFiveSatPerByteFee; | |||||
} else if (currency.defaultFee === 83.3) { | |||||
expectedHexByFee = sendBCHMock.expectedHexEightyThreeSatPerByteFee; | |||||
} | |||||
BCH.RawTransactions.sendRawTransaction = jest | BCH.RawTransactions.sendRawTransaction = jest | ||||
.fn() | .fn() | ||||
.mockResolvedValue(expectedTxId); | .mockResolvedValue(expectedTxId); | ||||
expect( | expect( | ||||
await sendBch(BCH, wallet, utxos, { addresses, values }, callback), | await sendBch(BCH, wallet, utxos, { addresses, values }, callback), | ||||
).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); | ).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); | ||||
expect(BCH.RawTransactions.sendRawTransaction).toHaveBeenCalledWith( | expect(BCH.RawTransactions.sendRawTransaction).toHaveBeenCalledWith( | ||||
expectedHexByFee, | expectedHex, | ||||
); | ); | ||||
expect(callback).toHaveBeenCalledWith(expectedTxId); | expect(callback).toHaveBeenCalledWith(expectedTxId); | ||||
}); | }); | ||||
it('sends BCH with less BCH available on balance', async () => { | it(`Throws error if called trying to send one satoshi ${currency.ticker} more than available in utxo set`, async () => { | ||||
const { sendBch } = useBCH(); | const { sendBch } = useBCH(); | ||||
const BCH = new BCHJS(); | const BCH = new BCHJS(); | ||||
const { | const { expectedTxId, utxos, wallet, addresses } = sendBCHMock; | ||||
expectedTxId, | |||||
expectedHex, | |||||
utxos, | |||||
wallet, | |||||
addresses, | |||||
} = sendBCHMock; | |||||
BCH.RawTransactions.sendRawTransaction = jest | BCH.RawTransactions.sendRawTransaction = jest | ||||
.fn() | .fn() | ||||
.mockResolvedValue(expectedTxId); | .mockResolvedValue(expectedTxId); | ||||
const oneBaseUnitMoreThanBalance = new BigNumber(utxos[0].value) | |||||
.minus(expectedOneOutputFee) | |||||
.plus(1) | |||||
.div(10 ** currency.cashDecimals) | |||||
.toString(); | |||||
const failedSendBch = sendBch(BCH, wallet, utxos, { | const failedSendBch = sendBch(BCH, wallet, utxos, { | ||||
addresses, | addresses, | ||||
values: [1], | values: [oneBaseUnitMoreThanBalance], | ||||
}); | }); | ||||
expect(failedSendBch).rejects.toThrow(new Error('Insufficient funds')); | expect(failedSendBch).rejects.toThrow(new Error('Insufficient funds')); | ||||
const nullValuesSendBch = await sendBch(BCH, wallet, utxos, { | const nullValuesSendBch = await sendBch(BCH, wallet, utxos, { | ||||
addresses, | addresses, | ||||
values: null, | values: null, | ||||
}); | }); | ||||
expect(nullValuesSendBch).toBe(null); | expect(nullValuesSendBch).toBe(null); | ||||
}); | }); | ||||
▲ Show 20 Lines • Show All 82 Lines • Show Last 20 Lines |