Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/src/hooks/__tests__/useBCH.test.js
Show All 36 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, 2, 1.01)).toBe(378); | ||||
if (currency.defaultFee === 3.01) { | |||||
expectedTxFee = 1126; | |||||
} else if (currency.defaultFee === 5.01) { | |||||
expectedTxFee = 1874; | |||||
} else if ((currency.defaultFee = 83.3)) { | |||||
expectedTxFee = 31155; | |||||
} | |||||
expect(calcFee(BCH, utxosMock)).toBe(expectedTxFee); | |||||
}); | }); | ||||
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, | expectedTxId, | ||||
expectedHex, | expectedHex, | ||||
utxos, | utxos, | ||||
wallet, | wallet, | ||||
addresses, | addresses, | ||||
values, | values, | ||||
} = sendBCHMock; | } = 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( | ||||
`${currency.blockExplorerUrl}/tx/${expectedTxId}`, | await sendBch(BCH, wallet, utxos, { addresses, values }, 1.01), | ||||
); | ).toBe(`${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, | expectedTxId, | ||||
expectedHex, | expectedHex, | ||||
utxos, | utxos, | ||||
wallet, | wallet, | ||||
addresses, | addresses, | ||||
values, | values, | ||||
} = sendBCHMock; | } = 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 }, | |||||
1.01, | |||||
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('sends BCH with less BCH available on balance', async () => { | ||||
const { sendBch } = useBCH(); | const { sendBch } = useBCH(); | ||||
const BCH = new BCHJS(); | const BCH = new BCHJS(); | ||||
const { | const { | ||||
expectedTxId, | expectedTxId, | ||||
expectedHex, | expectedHex, | ||||
utxos, | utxos, | ||||
wallet, | wallet, | ||||
addresses, | addresses, | ||||
} = sendBCHMock; | } = sendBCHMock; | ||||
BCH.RawTransactions.sendRawTransaction = jest | BCH.RawTransactions.sendRawTransaction = jest | ||||
.fn() | .fn() | ||||
.mockResolvedValue(expectedTxId); | .mockResolvedValue(expectedTxId); | ||||
const failedSendBch = sendBch(BCH, wallet, utxos, { | const failedSendBch = sendBch( | ||||
BCH, | |||||
wallet, | |||||
utxos, | |||||
{ | |||||
addresses, | addresses, | ||||
values: [1], | values: [1], | ||||
}); | }, | ||||
1.01, | |||||
); | |||||
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, | ||||
}); | }, | ||||
1.01, | |||||
); | |||||
expect(nullValuesSendBch).toBe(null); | expect(nullValuesSendBch).toBe(null); | ||||
}); | }); | ||||
it('Throws error on attempt to send one satoshi less than backend dust limit', async () => { | it('Throws error on attempt to send one satoshi less than backend dust limit', async () => { | ||||
const { sendBch } = useBCH(); | const { sendBch } = useBCH(); | ||||
const BCH = new BCHJS(); | const BCH = new BCHJS(); | ||||
const { expectedTxId, utxos, wallet, addresses } = sendBCHMock; | const { expectedTxId, utxos, wallet, addresses } = sendBCHMock; | ||||
BCH.RawTransactions.sendRawTransaction = jest | BCH.RawTransactions.sendRawTransaction = jest | ||||
.fn() | .fn() | ||||
.mockResolvedValue(expectedTxId); | .mockResolvedValue(expectedTxId); | ||||
const failedSendBch = sendBch(BCH, wallet, utxos, { | const failedSendBch = sendBch( | ||||
BCH, | |||||
wallet, | |||||
utxos, | |||||
{ | |||||
addresses, | addresses, | ||||
values: [ | values: [ | ||||
new BigNumber(currency.dust) | new BigNumber(currency.dust) | ||||
.minus(new BigNumber('0.00000001')) | .minus(new BigNumber('0.00000001')) | ||||
.toString(), | .toString(), | ||||
], | ], | ||||
}); | }, | ||||
1.01, | |||||
); | |||||
expect(failedSendBch).rejects.toThrow(new Error('dust')); | expect(failedSendBch).rejects.toThrow(new Error('dust')); | ||||
const nullValuesSendBch = await sendBch(BCH, wallet, utxos, { | const nullValuesSendBch = await sendBch( | ||||
BCH, | |||||
wallet, | |||||
utxos, | |||||
{ | |||||
addresses, | addresses, | ||||
values: null, | values: null, | ||||
}); | }, | ||||
1.01, | |||||
); | |||||
expect(nullValuesSendBch).toBe(null); | expect(nullValuesSendBch).toBe(null); | ||||
}); | }); | ||||
it('receives errors from the network and parses it', async () => { | it('receives errors from the network and parses it', async () => { | ||||
const { sendBch } = useBCH(); | const { sendBch } = useBCH(); | ||||
const BCH = new BCHJS(); | const BCH = new BCHJS(); | ||||
const { values, utxos, wallet, addresses } = sendBCHMock; | const { values, utxos, wallet, addresses } = sendBCHMock; | ||||
BCH.RawTransactions.sendRawTransaction = jest | BCH.RawTransactions.sendRawTransaction = jest | ||||
.fn() | .fn() | ||||
.mockImplementation(async () => { | .mockImplementation(async () => { | ||||
throw new Error('insufficient priority (code 66)'); | throw new Error('insufficient priority (code 66)'); | ||||
}); | }); | ||||
const insufficientPriority = sendBch(BCH, wallet, utxos, { | const insufficientPriority = sendBch( | ||||
BCH, | |||||
wallet, | |||||
utxos, | |||||
{ | |||||
addresses, | addresses, | ||||
values, | values, | ||||
}); | }, | ||||
1.01, | |||||
); | |||||
await expect(insufficientPriority).rejects.toThrow( | await expect(insufficientPriority).rejects.toThrow( | ||||
new Error('insufficient priority (code 66)'), | new Error('insufficient priority (code 66)'), | ||||
); | ); | ||||
BCH.RawTransactions.sendRawTransaction = jest | BCH.RawTransactions.sendRawTransaction = jest | ||||
.fn() | .fn() | ||||
.mockImplementation(async () => { | .mockImplementation(async () => { | ||||
throw new Error('txn-mempool-conflict (code 18)'); | throw new Error('txn-mempool-conflict (code 18)'); | ||||
}); | }); | ||||
const txnMempoolConflict = sendBch(BCH, wallet, utxos, { | const txnMempoolConflict = sendBch( | ||||
BCH, | |||||
wallet, | |||||
utxos, | |||||
{ | |||||
addresses, | addresses, | ||||
values, | values, | ||||
}); | }, | ||||
1.01, | |||||
); | |||||
await expect(txnMempoolConflict).rejects.toThrow( | await expect(txnMempoolConflict).rejects.toThrow( | ||||
new Error('txn-mempool-conflict (code 18)'), | new Error('txn-mempool-conflict (code 18)'), | ||||
); | ); | ||||
BCH.RawTransactions.sendRawTransaction = jest | BCH.RawTransactions.sendRawTransaction = jest | ||||
.fn() | .fn() | ||||
.mockImplementation(async () => { | .mockImplementation(async () => { | ||||
throw new Error('Network Error'); | throw new Error('Network Error'); | ||||
}); | }); | ||||
const networkError = sendBch(BCH, wallet, utxos, { addresses, values }); | const networkError = sendBch( | ||||
BCH, | |||||
wallet, | |||||
utxos, | |||||
{ addresses, values }, | |||||
1.01, | |||||
); | |||||
await expect(networkError).rejects.toThrow(new Error('Network Error')); | await expect(networkError).rejects.toThrow(new Error('Network Error')); | ||||
BCH.RawTransactions.sendRawTransaction = jest | BCH.RawTransactions.sendRawTransaction = jest | ||||
.fn() | .fn() | ||||
.mockImplementation(async () => { | .mockImplementation(async () => { | ||||
const err = new Error( | const err = new Error( | ||||
'too-long-mempool-chain, too many unconfirmed ancestors [limit: 25] (code 64)', | 'too-long-mempool-chain, too many unconfirmed ancestors [limit: 25] (code 64)', | ||||
); | ); | ||||
throw err; | throw err; | ||||
}); | }); | ||||
const tooManyAncestorsMempool = sendBch(BCH, wallet, utxos, { | const tooManyAncestorsMempool = sendBch( | ||||
BCH, | |||||
wallet, | |||||
utxos, | |||||
{ | |||||
addresses, | addresses, | ||||
values, | values, | ||||
}); | }, | ||||
1.01, | |||||
); | |||||
await expect(tooManyAncestorsMempool).rejects.toThrow( | await expect(tooManyAncestorsMempool).rejects.toThrow( | ||||
new Error( | new Error( | ||||
'too-long-mempool-chain, too many unconfirmed ancestors [limit: 25] (code 64)', | 'too-long-mempool-chain, too many unconfirmed ancestors [limit: 25] (code 64)', | ||||
), | ), | ||||
); | ); | ||||
}); | }); | ||||
}); | }); |