Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/src/hooks/__tests__/useBCH.test.js
Show All 18 Lines | it('gets primary Rest API URL on mainnet', () => { | ||||
}; | }; | ||||
const { getRestUrl } = useBCH(); | const { getRestUrl } = useBCH(); | ||||
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('sends XEC correctly', async () => { | it('sends XEC correctly', async () => { | ||||
const { sendXec } = useBCH(); | const { sendXec } = useBCH(); | ||||
const BCH = new BCHJS(); | |||||
const chronik = new ChronikClient( | const chronik = new ChronikClient( | ||||
'https://FakeChronikUrlToEnsureMocksOnly.com', | 'https://FakeChronikUrlToEnsureMocksOnly.com', | ||||
); | ); | ||||
const { expectedTxId, utxos, wallet, destinationAddress, sendAmount } = | const { expectedTxId, utxos, wallet, destinationAddress, sendAmount } = | ||||
sendBCHMock; | sendBCHMock; | ||||
chronik.broadcastTx = jest | chronik.broadcastTx = jest | ||||
.fn() | .fn() | ||||
.mockResolvedValue({ txid: expectedTxId }); | .mockResolvedValue({ txid: expectedTxId }); | ||||
expect( | expect( | ||||
await sendXec( | await sendXec( | ||||
BCH, | |||||
chronik, | chronik, | ||||
wallet, | wallet, | ||||
utxos, | utxos, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
'', | '', | ||||
false, | false, | ||||
null, | null, | ||||
destinationAddress, | destinationAddress, | ||||
sendAmount, | sendAmount, | ||||
), | ), | ||||
).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); | ).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); | ||||
}); | }); | ||||
it('sends XEC correctly with an encrypted OP_RETURN message', async () => { | it('sends XEC correctly with an encrypted OP_RETURN message', async () => { | ||||
const { sendXec } = useBCH(); | const { sendXec } = useBCH(); | ||||
const BCH = new BCHJS(); | |||||
const chronik = new ChronikClient( | const chronik = new ChronikClient( | ||||
'https://FakeChronikUrlToEnsureMocksOnly.com', | 'https://FakeChronikUrlToEnsureMocksOnly.com', | ||||
); | ); | ||||
const { expectedTxId, utxos, wallet, destinationAddress, sendAmount } = | const { expectedTxId, utxos, wallet, destinationAddress, sendAmount } = | ||||
sendBCHMock; | sendBCHMock; | ||||
const expectedPubKey = | const expectedPubKey = | ||||
'03451a3e61ae8eb76b8d4cd6057e4ebaf3ef63ae3fe5f441b72c743b5810b6a389'; | '03451a3e61ae8eb76b8d4cd6057e4ebaf3ef63ae3fe5f441b72c743b5810b6a389'; | ||||
chronik.broadcastTx = jest | chronik.broadcastTx = jest | ||||
.fn() | .fn() | ||||
.mockResolvedValue({ txid: expectedTxId }); | .mockResolvedValue({ txid: expectedTxId }); | ||||
expect( | expect( | ||||
await sendXec( | await sendXec( | ||||
BCH, | |||||
chronik, | chronik, | ||||
wallet, | wallet, | ||||
utxos, | utxos, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
'This is an encrypted opreturn message', | 'This is an encrypted opreturn message', | ||||
false, | false, | ||||
null, | null, | ||||
destinationAddress, | destinationAddress, | ||||
sendAmount, | sendAmount, | ||||
true, // encryption flag for the OP_RETURN message | true, // encryption flag for the OP_RETURN message | ||||
false, // airdrop flag | false, // airdrop flag | ||||
'', // airdrop token id | '', // airdrop token id | ||||
expectedPubKey, //optionalMockPubKeyResponse | expectedPubKey, //optionalMockPubKeyResponse | ||||
), | ), | ||||
).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); | ).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); | ||||
}); | }); | ||||
it('sends one to many XEC correctly', async () => { | it('sends one to many XEC correctly', async () => { | ||||
const { sendXec } = useBCH(); | const { sendXec } = useBCH(); | ||||
const BCH = new BCHJS(); | |||||
const chronik = new ChronikClient( | const chronik = new ChronikClient( | ||||
'https://FakeChronikUrlToEnsureMocksOnly.com', | 'https://FakeChronikUrlToEnsureMocksOnly.com', | ||||
); | ); | ||||
const { expectedTxId, utxos, wallet } = sendBCHMock; | const { expectedTxId, utxos, wallet } = sendBCHMock; | ||||
const addressAndValueArray = [ | const addressAndValueArray = [ | ||||
'bitcoincash:qrzuvj0vvnsz5949h4axercl5k420eygavv0awgz05,6', | 'bitcoincash:qrzuvj0vvnsz5949h4axercl5k420eygavv0awgz05,6', | ||||
'bitcoincash:qrzuvj0vvnsz5949h4axercl5k420eygavv0awgz05,6.8', | 'bitcoincash:qrzuvj0vvnsz5949h4axercl5k420eygavv0awgz05,6.8', | ||||
'bitcoincash:qrzuvj0vvnsz5949h4axercl5k420eygavv0awgz05,7', | 'bitcoincash:qrzuvj0vvnsz5949h4axercl5k420eygavv0awgz05,7', | ||||
'bitcoincash:qrzuvj0vvnsz5949h4axercl5k420eygavv0awgz05,6', | 'bitcoincash:qrzuvj0vvnsz5949h4axercl5k420eygavv0awgz05,6', | ||||
]; | ]; | ||||
chronik.broadcastTx = jest | chronik.broadcastTx = jest | ||||
.fn() | .fn() | ||||
.mockResolvedValue({ txid: expectedTxId }); | .mockResolvedValue({ txid: expectedTxId }); | ||||
expect( | expect( | ||||
await sendXec( | await sendXec( | ||||
BCH, | |||||
chronik, | chronik, | ||||
wallet, | wallet, | ||||
utxos, | utxos, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
'', | '', | ||||
true, | true, | ||||
addressAndValueArray, | addressAndValueArray, | ||||
), | ), | ||||
).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); | ).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); | ||||
}); | }); | ||||
it(`Throws error if called trying to send one base unit ${currency.ticker} more than available in utxo set`, async () => { | it(`Throws error if called trying to send one base unit ${currency.ticker} more than available in utxo set`, async () => { | ||||
const { sendXec } = useBCH(); | const { sendXec } = useBCH(); | ||||
const BCH = new BCHJS(); | |||||
const chronik = new ChronikClient( | const chronik = new ChronikClient( | ||||
'https://FakeChronikUrlToEnsureMocksOnly.com', | 'https://FakeChronikUrlToEnsureMocksOnly.com', | ||||
); | ); | ||||
const { utxos, wallet, destinationAddress } = sendBCHMock; | const { utxos, wallet, destinationAddress } = sendBCHMock; | ||||
const expectedTxFeeInSats = 229; | const expectedTxFeeInSats = 229; | ||||
// tally up the total utxo values | // tally up the total utxo values | ||||
let totalInputUtxoValue = new BigNumber(0); | let totalInputUtxoValue = new BigNumber(0); | ||||
for (let i = 0; i < utxos.length; i++) { | for (let i = 0; i < utxos.length; i++) { | ||||
totalInputUtxoValue = totalInputUtxoValue.plus( | totalInputUtxoValue = totalInputUtxoValue.plus( | ||||
new BigNumber(utxos[i].value), | new BigNumber(utxos[i].value), | ||||
); | ); | ||||
} | } | ||||
const oneBaseUnitMoreThanBalance = totalInputUtxoValue | const oneBaseUnitMoreThanBalance = totalInputUtxoValue | ||||
.minus(expectedTxFeeInSats) | .minus(expectedTxFeeInSats) | ||||
.plus(1) | .plus(1) | ||||
.div(10 ** currency.cashDecimals) | .div(10 ** currency.cashDecimals) | ||||
.toString(); | .toString(); | ||||
let errorThrown; | let errorThrown; | ||||
try { | try { | ||||
await sendXec( | await sendXec( | ||||
BCH, | |||||
chronik, | chronik, | ||||
wallet, | wallet, | ||||
utxos, | utxos, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
'', | '', | ||||
false, | false, | ||||
null, | null, | ||||
destinationAddress, | destinationAddress, | ||||
oneBaseUnitMoreThanBalance, | oneBaseUnitMoreThanBalance, | ||||
); | ); | ||||
} catch (err) { | } catch (err) { | ||||
errorThrown = err; | errorThrown = err; | ||||
} | } | ||||
expect(errorThrown.message).toStrictEqual('Insufficient funds'); | expect(errorThrown.message).toStrictEqual('Insufficient funds'); | ||||
const nullValuesSendBch = sendXec( | const nullValuesSendBch = sendXec( | ||||
BCH, | |||||
chronik, | chronik, | ||||
wallet, | wallet, | ||||
utxos, | utxos, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
'', | '', | ||||
false, | false, | ||||
null, | null, | ||||
destinationAddress, | destinationAddress, | ||||
null, | null, | ||||
); | ); | ||||
expect(nullValuesSendBch).rejects.toThrow( | expect(nullValuesSendBch).rejects.toThrow( | ||||
new Error('Invalid singleSendValue'), | new Error('Invalid singleSendValue'), | ||||
); | ); | ||||
}); | }); | ||||
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 { sendXec } = useBCH(); | const { sendXec } = useBCH(); | ||||
const BCH = new BCHJS(); | |||||
const chronik = new ChronikClient( | const chronik = new ChronikClient( | ||||
'https://FakeChronikUrlToEnsureMocksOnly.com', | 'https://FakeChronikUrlToEnsureMocksOnly.com', | ||||
); | ); | ||||
const { utxos, wallet, destinationAddress } = sendBCHMock; | const { utxos, wallet, destinationAddress } = sendBCHMock; | ||||
const failedSendBch = sendXec( | const failedSendBch = sendXec( | ||||
BCH, | |||||
chronik, | chronik, | ||||
wallet, | wallet, | ||||
utxos, | utxos, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
'', | '', | ||||
false, | false, | ||||
null, | null, | ||||
destinationAddress, | destinationAddress, | ||||
Show All 25 Lines | it("Throws error attempting to burn an eToken ID that is not within the wallet's utxo", async () => { | ||||
} catch (err) { | } catch (err) { | ||||
thrownError = err; | thrownError = err; | ||||
} | } | ||||
expect(thrownError).toStrictEqual(new Error(expectedError)); | expect(thrownError).toStrictEqual(new Error(expectedError)); | ||||
}); | }); | ||||
it('receives errors from the network and parses it', async () => { | it('receives errors from the network and parses it', async () => { | ||||
const { sendXec } = useBCH(); | const { sendXec } = useBCH(); | ||||
const BCH = new BCHJS(); | |||||
const chronik = new ChronikClient( | const chronik = new ChronikClient( | ||||
'https://FakeChronikUrlToEnsureMocksOnly.com', | 'https://FakeChronikUrlToEnsureMocksOnly.com', | ||||
); | ); | ||||
const { sendAmount, utxos, wallet, destinationAddress } = sendBCHMock; | const { sendAmount, utxos, wallet, destinationAddress } = sendBCHMock; | ||||
chronik.broadcastTx = jest.fn().mockImplementation(async () => { | chronik.broadcastTx = jest.fn().mockImplementation(async () => { | ||||
throw new Error('insufficient priority (code 66)'); | throw new Error('insufficient priority (code 66)'); | ||||
}); | }); | ||||
const insufficientPriority = sendXec( | const insufficientPriority = sendXec( | ||||
BCH, | |||||
chronik, | chronik, | ||||
wallet, | wallet, | ||||
utxos, | utxos, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
'', | '', | ||||
false, | false, | ||||
null, | null, | ||||
destinationAddress, | destinationAddress, | ||||
sendAmount, | sendAmount, | ||||
); | ); | ||||
await expect(insufficientPriority).rejects.toThrow( | await expect(insufficientPriority).rejects.toThrow( | ||||
new Error('insufficient priority (code 66)'), | new Error('insufficient priority (code 66)'), | ||||
); | ); | ||||
chronik.broadcastTx = jest.fn().mockImplementation(async () => { | chronik.broadcastTx = jest.fn().mockImplementation(async () => { | ||||
throw new Error('txn-mempool-conflict (code 18)'); | throw new Error('txn-mempool-conflict (code 18)'); | ||||
}); | }); | ||||
const txnMempoolConflict = sendXec( | const txnMempoolConflict = sendXec( | ||||
BCH, | |||||
chronik, | chronik, | ||||
wallet, | wallet, | ||||
utxos, | utxos, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
'', | '', | ||||
false, | false, | ||||
null, | null, | ||||
destinationAddress, | destinationAddress, | ||||
sendAmount, | sendAmount, | ||||
); | ); | ||||
await expect(txnMempoolConflict).rejects.toThrow( | await expect(txnMempoolConflict).rejects.toThrow( | ||||
new Error('txn-mempool-conflict (code 18)'), | new Error('txn-mempool-conflict (code 18)'), | ||||
); | ); | ||||
chronik.broadcastTx = jest.fn().mockImplementation(async () => { | chronik.broadcastTx = jest.fn().mockImplementation(async () => { | ||||
throw new Error('Network Error'); | throw new Error('Network Error'); | ||||
}); | }); | ||||
const networkError = sendXec( | const networkError = sendXec( | ||||
BCH, | |||||
chronik, | chronik, | ||||
wallet, | wallet, | ||||
utxos, | utxos, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
'', | '', | ||||
false, | false, | ||||
null, | null, | ||||
destinationAddress, | destinationAddress, | ||||
sendAmount, | sendAmount, | ||||
); | ); | ||||
await expect(networkError).rejects.toThrow(new Error('Network Error')); | await expect(networkError).rejects.toThrow(new Error('Network Error')); | ||||
chronik.broadcastTx = jest.fn().mockImplementation(async () => { | chronik.broadcastTx = jest.fn().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 = sendXec( | const tooManyAncestorsMempool = sendXec( | ||||
BCH, | |||||
chronik, | chronik, | ||||
wallet, | wallet, | ||||
utxos, | utxos, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
'', | '', | ||||
false, | false, | ||||
null, | null, | ||||
destinationAddress, | destinationAddress, | ||||
▲ Show 20 Lines • Show All 63 Lines • Show Last 20 Lines |